From 69b37d878b23934aec8530c696ff8a7eafac2d48 Mon Sep 17 00:00:00 2001 From: Zapper9982 Date: Sat, 16 Aug 2025 02:35:25 +0530 Subject: [PATCH 001/237] test(controller): Complete testcases for Controllers of FLW --- pom.xml | 40 +- .../java/com/iemr/flw/FlwApplicationTest.java | 13 - .../controller/BeneficiaryControllerTest.java | 75 ++ .../flw/controller/CbacControllerTest.java | 121 +++ .../controller/ChildCareControllerTest.java | 339 +++++++ .../flw/controller/CoupleControllerTest.java | 396 ++++---- .../DeathReportsControllerTest.java | 214 ++++ .../controller/HighRiskControllerTest.java | 439 ++++++++ .../controller/IncentiveControllerTest.java | 163 +++ .../MaternalHealthControllerTest.java | 945 ++++++++++-------- .../iemr/flw/controller/TBControllerTest.java | 222 ++++ .../flw/controller/UserControllerTest.java | 80 +- .../service/impl/CoupleServiceImplTest.java | 142 --- .../impl/DeliveryOutcomeServiceImplTest.java | 75 -- .../service/impl/InfantServiceImplTest.java | 75 -- .../impl/MaternalHealthServiceImplTest.java | 106 -- .../flw/service/impl/UserServiceImplTest.java | 51 - 17 files changed, 2351 insertions(+), 1145 deletions(-) delete mode 100644 src/test/java/com/iemr/flw/FlwApplicationTest.java create mode 100644 src/test/java/com/iemr/flw/controller/BeneficiaryControllerTest.java create mode 100644 src/test/java/com/iemr/flw/controller/CbacControllerTest.java create mode 100644 src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java create mode 100644 src/test/java/com/iemr/flw/controller/DeathReportsControllerTest.java create mode 100644 src/test/java/com/iemr/flw/controller/HighRiskControllerTest.java create mode 100644 src/test/java/com/iemr/flw/controller/IncentiveControllerTest.java create mode 100644 src/test/java/com/iemr/flw/controller/TBControllerTest.java delete mode 100644 src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java delete mode 100644 src/test/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImplTest.java delete mode 100644 src/test/java/com/iemr/flw/service/impl/InfantServiceImplTest.java delete mode 100644 src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java delete mode 100644 src/test/java/com/iemr/flw/service/impl/UserServiceImplTest.java diff --git a/pom.xml b/pom.xml index 265e70535..4562e4fa0 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ ${ENV_VAR} target/classes/application.properties target/classes/common_${environment}.properties - true + false target @@ -218,11 +218,6 @@ org.slf4j slf4j-api - - org.jacoco - jacoco-maven-plugin - 0.8.11 - org.springframework spring-web @@ -274,15 +269,30 @@ ${artifactId}-${version} - - org.apache.maven.plugins - maven-jar-plugin - 3.0.2 - - - org.springframework.boot - spring-boot-maven-plugin - + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + + prepare-agent + + + + report + test + + report + + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/src/test/java/com/iemr/flw/FlwApplicationTest.java b/src/test/java/com/iemr/flw/FlwApplicationTest.java deleted file mode 100644 index 7ce759d2c..000000000 --- a/src/test/java/com/iemr/flw/FlwApplicationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.iemr.flw; - - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -public class FlwApplicationTest { - - @Test - public void contextLoads() { - } -} \ No newline at end of file diff --git a/src/test/java/com/iemr/flw/controller/BeneficiaryControllerTest.java b/src/test/java/com/iemr/flw/controller/BeneficiaryControllerTest.java new file mode 100644 index 000000000..056791158 --- /dev/null +++ b/src/test/java/com/iemr/flw/controller/BeneficiaryControllerTest.java @@ -0,0 +1,75 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.service.BeneficiaryService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class BeneficiaryControllerTest { + private MockMvc mockMvc; + + @Mock + private BeneficiaryService beneficiaryService; + + @InjectMocks + private BeneficiaryController controller; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void getBeneficiaryDataByAsha_success() throws Exception { + GetBenRequestHandler req = new GetBenRequestHandler(); + when(beneficiaryService.getBenData(any(), anyString())).thenReturn("data"); + mockMvc.perform(post("/beneficiary/getBeneficiaryData") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void getBeneficiaryDataByAsha_noRecordFound() throws Exception { + GetBenRequestHandler req = new GetBenRequestHandler(); + when(beneficiaryService.getBenData(any(), anyString())).thenReturn(null); + mockMvc.perform(post("/beneficiary/getBeneficiaryData") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void getBeneficiaryDataByAsha_invalidRequest() throws Exception { + mockMvc.perform(post("/beneficiary/getBeneficiaryData") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getBeneficiaryDataByAsha_exception() throws Exception { + when(beneficiaryService.getBenData(any(), anyString())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/beneficiary/getBeneficiaryData") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/iemr/flw/controller/CbacControllerTest.java b/src/test/java/com/iemr/flw/controller/CbacControllerTest.java new file mode 100644 index 000000000..ed24fd5c7 --- /dev/null +++ b/src/test/java/com/iemr/flw/controller/CbacControllerTest.java @@ -0,0 +1,121 @@ +package com.iemr.flw.controller; + +import com.google.gson.Gson; +import com.iemr.flw.dto.identity.CbacDTO; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.service.CbacService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import java.util.Collections; +import java.util.List; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class CbacControllerTest { + private MockMvc mockMvc; + + @Mock + private CbacService cbacService; + + @InjectMocks + private CbacController controller; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void getAllCbacDetailsByUserId_success() throws Exception { + when(cbacService.getByUserId(any())).thenReturn("data"); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/cbac/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllCbacDetailsByUserId_noRecordFound() throws Exception { + when(cbacService.getByUserId(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/cbac/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllCbacDetailsByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/cbac/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getAllCbacDetailsByUserId_exception() throws Exception { + when(cbacService.getByUserId(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/cbac/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveAllCbacDetailsByUserId_success() throws Exception { + List dtos = Collections.singletonList(new CbacDTO()); + when(cbacService.save(any())).thenReturn("data"); + mockMvc.perform(post("/cbac/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveAllCbacDetailsByUserId_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new CbacDTO()); + when(cbacService.save(any())).thenReturn(null); + mockMvc.perform(post("/cbac/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveAllCbacDetailsByUserId_invalidRequest() throws Exception { + List dtos = Collections.emptyList(); + mockMvc.perform(post("/cbac/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveAllCbacDetailsByUserId_exception() throws Exception { + List dtos = Collections.singletonList(new CbacDTO()); + when(cbacService.save(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/cbac/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java b/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java new file mode 100644 index 000000000..814e517c2 --- /dev/null +++ b/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java @@ -0,0 +1,339 @@ +package com.iemr.flw.controller; + +import com.google.gson.Gson; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.service.ChildCareService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import java.util.Collections; +import java.util.List; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class ChildCareControllerTest { + private MockMvc mockMvc; + + @Mock + private ChildCareService childCareService; + + @InjectMocks + private ChildCareController controller; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void saveHbycRecords_success() throws Exception { + List dtos = Collections.singletonList(new HbycDTO()); + when(childCareService.registerHBYC(any())).thenReturn("data"); + mockMvc.perform(post("/child-care/hbyc/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveHbycRecords_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new HbycDTO()); + when(childCareService.registerHBYC(any())).thenReturn(null); + mockMvc.perform(post("/child-care/hbyc/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + + @Test + void saveHbycRecords_invalidRequest() throws Exception { + mockMvc.perform(post("/child-care/hbyc/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveHbycRecords_exception() throws Exception { + List dtos = Collections.singletonList(new HbycDTO()); + when(childCareService.registerHBYC(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/child-care/hbyc/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getHbycRecords_success() throws Exception { + when(childCareService.getHbycRecords(any())).thenReturn(Collections.singletonList(new HbycDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/hbyc/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getHbycRecords_noRecordFound() throws Exception { + when(childCareService.getHbycRecords(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/hbyc/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getHbycRecords_invalidRequest() throws Exception { + mockMvc.perform(post("/child-care/hbyc/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getHbycRecords_exception() throws Exception { + when(childCareService.getHbycRecords(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/hbyc/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveHBNCVisit_success() throws Exception { + List dtos = Collections.singletonList(new HbncRequestDTO()); + when(childCareService.saveHBNCDetails(any())).thenReturn("data"); + mockMvc.perform(post("/child-care/hbncVisit/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveHBNCVisit_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new HbncRequestDTO()); + when(childCareService.saveHBNCDetails(any())).thenReturn(null); + mockMvc.perform(post("/child-care/hbncVisit/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("Saving hbnc data to db failed"); + }); + } + + @Test + void saveHBNCVisit_invalidRequest() throws Exception { + mockMvc.perform(post("/child-care/hbncVisit/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("[]")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("Invalid/NULL request obj"); + }); + } + + @Test + void saveHBNCVisit_exception() throws Exception { + List dtos = Collections.singletonList(new HbncRequestDTO()); + when(childCareService.saveHBNCDetails(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/child-care/hbncVisit/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getHBNCVisitDetails_success() throws Exception { + when(childCareService.getHBNCDetails(any())).thenReturn(Collections.singletonList(new HbncRequestDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/hbncVisit/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getHBNCVisitDetails_noRecordFound() throws Exception { + when(childCareService.getHBNCDetails(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/hbncVisit/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getHBNCVisitDetails_invalidRequest() throws Exception { + mockMvc.perform(post("/child-care/hbncVisit/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getHBNCVisitDetails_exception() throws Exception { + when(childCareService.getHBNCDetails(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/hbncVisit/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveChildVaccinationDetails_success() throws Exception { + List dtos = Collections.singletonList(new ChildVaccinationDTO()); + when(childCareService.saveChildVaccinationDetails(any())).thenReturn("data"); + mockMvc.perform(post("/child-care/vaccination/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveChildVaccinationDetails_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new ChildVaccinationDTO()); + when(childCareService.saveChildVaccinationDetails(any())).thenReturn(null); + mockMvc.perform(post("/child-care/vaccination/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("Saving Child vaccination data to db failed"); + }); + } + + @Test + void saveChildVaccinationDetails_invalidRequest() throws Exception { + mockMvc.perform(post("/child-care/vaccination/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("[]")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("Invalid/NULL request obj"); + }); + } + + @Test + void saveChildVaccinationDetails_exception() throws Exception { + List dtos = Collections.singletonList(new ChildVaccinationDTO()); + when(childCareService.saveChildVaccinationDetails(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/child-care/vaccination/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getChildVaccinationDetails_success() throws Exception { + when(childCareService.getChildVaccinationDetails(any())).thenReturn(Collections.singletonList(new ChildVaccinationDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/vaccination/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getChildVaccinationDetails_noRecordFound() throws Exception { + when(childCareService.getChildVaccinationDetails(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/vaccination/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getChildVaccinationDetails_invalidRequest() throws Exception { + mockMvc.perform(post("/child-care/vaccination/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getChildVaccinationDetails_exception() throws Exception { + when(childCareService.getChildVaccinationDetails(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/child-care/vaccination/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllChildVaccines_success() throws Exception { + when(childCareService.getAllChildVaccines(any())).thenReturn(Collections.singletonList(new VaccineDTO())); + mockMvc.perform(get("/child-care/vaccine/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .param("category", "cat1")) + .andExpect(status().isOk()); + } + + @Test + void getAllChildVaccines_noRecordFound() throws Exception { + when(childCareService.getAllChildVaccines(any())).thenReturn(null); + mockMvc.perform(get("/child-care/vaccine/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .param("category", "cat1")) + .andExpect(status().isOk()); + } + + @Test + void getAllChildVaccines_exception() throws Exception { + when(childCareService.getAllChildVaccines(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(get("/child-care/vaccine/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .param("category", "cat1")) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/iemr/flw/controller/CoupleControllerTest.java b/src/test/java/com/iemr/flw/controller/CoupleControllerTest.java index b4cf29e84..61895098e 100644 --- a/src/test/java/com/iemr/flw/controller/CoupleControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/CoupleControllerTest.java @@ -1,233 +1,205 @@ package com.iemr.flw.controller; -import static org.mockito.Mockito.*; - +import com.google.gson.Gson; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.EligibleCoupleDTO; import com.iemr.flw.dto.iemr.EligibleCoupleTrackingDTO; import com.iemr.flw.service.CoupleService; -import com.iemr.flw.utils.ApiResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -import java.util.Arrays; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import java.util.Collections; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; class CoupleControllerTest { - - @InjectMocks - private CoupleController coupleController; + private MockMvc mockMvc; @Mock private CoupleService coupleService; + @InjectMocks + private CoupleController controller; + @BeforeEach void setUp() { - MockitoAnnotations.initMocks(this); - } - -// @Test -// void testSaveEligibleCouple() { -// // Arrange -// List eligibleCoupleDTOs = Arrays.asList(new EligibleCoupleDTO()); -// -// when(coupleService.registerEligibleCouple(any())).thenReturn("Save successful"); -// -// // Act -// ResponseEntity responseEntity = coupleController.saveEligibleCouple(eligibleCoupleDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals("Save successful", apiResponse.getData()); -// -// verify(coupleService, times(1)).registerEligibleCouple(eligibleCoupleDTOs); -// } -// -// @Test -// void testSaveEligibleCouple_Exception() { -// // Arrange -// List eligibleCoupleDTOs = Arrays.asList(new EligibleCoupleDTO()); -// -// when(coupleService.registerEligibleCouple(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = coupleController.saveEligibleCouple(eligibleCoupleDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(coupleService, times(1)).registerEligibleCouple(eligibleCoupleDTOs); -// } -// -// @Test -// void testGetEligibleCouple() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(198); -// -// List responseDTOs = Arrays.asList(new EligibleCoupleDTO()); -// when(coupleService.getEligibleCoupleRegRecords(any())).thenReturn(responseDTOs); -// -// // Act -// ResponseEntity responseEntity = coupleController.getEligibleCouple(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals(responseDTOs, apiResponse.getData()); -// -// verify(coupleService, times(1)).getEligibleCoupleRegRecords(requestDTO); -// } -// -// @Test -// void testGetEligibleCouple_Exception() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1098); -// -// when(coupleService.getEligibleCoupleRegRecords(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = coupleController.getEligibleCouple(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(coupleService, times(1)).getEligibleCoupleRegRecords(requestDTO); -// } -// -// @Test -// void testSaveEligibleCoupleTracking() { -// // Arrange -// List eligibleCoupleTrackingDTOS = Arrays.asList(new EligibleCoupleTrackingDTO()); -// -// when(coupleService.registerEligibleCoupleTracking(any())).thenReturn("Save successful"); -// -// // Act -// ResponseEntity responseEntity = coupleController.saveEligibleCoupleTracking(eligibleCoupleTrackingDTOS, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals("Save successful", apiResponse.getData()); -// -// verify(coupleService, times(1)).registerEligibleCoupleTracking(eligibleCoupleTrackingDTOS); -// } -// -// @Test -// void testSaveEligibleCoupleTracking_Exception() { -// // Arrange -// List eligibleCoupleTrackingDTOS = Arrays.asList(new EligibleCoupleTrackingDTO()); -// -// when(coupleService.registerEligibleCoupleTracking(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = coupleController.saveEligibleCoupleTracking(eligibleCoupleTrackingDTOS, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(coupleService, times(1)).registerEligibleCoupleTracking(eligibleCoupleTrackingDTOS); -// } -// -// @Test -// void testGetEligibleCoupleTracking() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1298); -// -// List responseDTOs = Arrays.asList(new EligibleCoupleTrackingDTO()); -// when(coupleService.getEligibleCoupleTracking(any())).thenReturn(responseDTOs); -// -// // Act -// ResponseEntity responseEntity = coupleController.getEligibleCoupleTracking(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals(responseDTOs, apiResponse.getData()); -// -// verify(coupleService, times(1)).getEligibleCoupleTracking(requestDTO); -// } -// -// @Test -// void testGetEligibleCoupleTracking_Exception() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1028); -// -// when(coupleService.getEligibleCoupleTracking(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = coupleController.getEligibleCoupleTracking(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(coupleService, times(1)).getEligibleCoupleTracking(requestDTO); -// } + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void saveEligibleCouple_success() throws Exception { + List dtos = Collections.singletonList(new EligibleCoupleDTO()); + when(coupleService.registerEligibleCouple(any())).thenReturn("data"); + mockMvc.perform(post("/couple/register/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveEligibleCouple_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new EligibleCoupleDTO()); + when(coupleService.registerEligibleCouple(any())).thenReturn(null); + mockMvc.perform(post("/couple/register/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveEligibleCouple_invalidRequest() throws Exception { + mockMvc.perform(post("/couple/register/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveEligibleCouple_exception() throws Exception { + List dtos = Collections.singletonList(new EligibleCoupleDTO()); + when(coupleService.registerEligibleCouple(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/couple/register/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveEligibleCoupleTracking_success() throws Exception { + List dtos = Collections.singletonList(new EligibleCoupleTrackingDTO()); + when(coupleService.registerEligibleCoupleTracking(any())).thenReturn("data"); + mockMvc.perform(post("/couple/tracking/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveEligibleCoupleTracking_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new EligibleCoupleTrackingDTO()); + when(coupleService.registerEligibleCoupleTracking(any())).thenReturn(null); + mockMvc.perform(post("/couple/tracking/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveEligibleCoupleTracking_invalidRequest() throws Exception { + mockMvc.perform(post("/couple/tracking/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveEligibleCoupleTracking_exception() throws Exception { + List dtos = Collections.singletonList(new EligibleCoupleTrackingDTO()); + when(coupleService.registerEligibleCoupleTracking(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/couple/tracking/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getEligibleCouple_success() throws Exception { + when(coupleService.getEligibleCoupleRegRecords(any())).thenReturn("data"); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/couple/register/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getEligibleCouple_noRecordFound() throws Exception { + when(coupleService.getEligibleCoupleRegRecords(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/couple/register/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getEligibleCouple_invalidRequest() throws Exception { + mockMvc.perform(post("/couple/register/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getEligibleCouple_exception() throws Exception { + when(coupleService.getEligibleCoupleRegRecords(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/couple/register/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getEligibleCoupleTracking_success() throws Exception { + when(coupleService.getEligibleCoupleTracking(any())).thenReturn(Collections.singletonList(new EligibleCoupleTrackingDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/couple/tracking/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getEligibleCoupleTracking_noRecordFound() throws Exception { + when(coupleService.getEligibleCoupleTracking(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/couple/tracking/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getEligibleCoupleTracking_invalidRequest() throws Exception { + mockMvc.perform(post("/couple/tracking/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getEligibleCoupleTracking_exception() throws Exception { + when(coupleService.getEligibleCoupleTracking(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/couple/tracking/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } } diff --git a/src/test/java/com/iemr/flw/controller/DeathReportsControllerTest.java b/src/test/java/com/iemr/flw/controller/DeathReportsControllerTest.java new file mode 100644 index 000000000..f41b6a5e5 --- /dev/null +++ b/src/test/java/com/iemr/flw/controller/DeathReportsControllerTest.java @@ -0,0 +1,214 @@ +package com.iemr.flw.controller; + +import com.google.gson.Gson; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.CdrDTO; +import com.iemr.flw.dto.iemr.MdsrDTO; +import com.iemr.flw.service.DeathReportsService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import java.util.Collections; +import java.util.List; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class DeathReportsControllerTest { + private MockMvc mockMvc; + + @Mock + private DeathReportsService deathReportsService; + + @InjectMocks + private DeathReportsController controller; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void saveCdrRecords_success() throws Exception { + List dtos = Collections.singletonList(new CdrDTO()); + when(deathReportsService.registerCDR(any())).thenReturn("data"); + mockMvc.perform(post("/death-reports/cdr/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveCdrRecords_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new CdrDTO()); + when(deathReportsService.registerCDR(any())).thenReturn(null); + mockMvc.perform(post("/death-reports/cdr/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + + @Test + void saveCdrRecords_invalidRequest() throws Exception { + mockMvc.perform(post("/death-reports/cdr/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveCdrRecords_exception() throws Exception { + List dtos = Collections.singletonList(new CdrDTO()); + when(deathReportsService.registerCDR(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/death-reports/cdr/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveMdsrRecords_success() throws Exception { + List dtos = Collections.singletonList(new MdsrDTO()); + when(deathReportsService.registerMDSR(any())).thenReturn("data"); + mockMvc.perform(post("/death-reports/mdsr/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveMdsrRecords_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new MdsrDTO()); + when(deathReportsService.registerMDSR(any())).thenReturn(null); + mockMvc.perform(post("/death-reports/mdsr/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + + @Test + void saveMdsrRecords_invalidRequest() throws Exception { + mockMvc.perform(post("/death-reports/mdsr/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveMdsrRecords_exception() throws Exception { + List dtos = Collections.singletonList(new MdsrDTO()); + when(deathReportsService.registerMDSR(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/death-reports/mdsr/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getCdrRecords_success() throws Exception { + when(deathReportsService.getCdrRecords(any())).thenReturn(Collections.singletonList(new CdrDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/death-reports/cdr/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getCdrRecords_noRecordFound() throws Exception { + when(deathReportsService.getCdrRecords(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/death-reports/cdr/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + + } + + @Test + void getCdrRecords_invalidRequest() throws Exception { + mockMvc.perform(post("/death-reports/cdr/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getCdrRecords_exception() throws Exception { + when(deathReportsService.getCdrRecords(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/death-reports/cdr/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getMdsrRecords_success() throws Exception { + when(deathReportsService.getMdsrRecords(any())).thenReturn(Collections.singletonList(new MdsrDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/death-reports/mdsr/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getMdsrRecords_noRecordFound() throws Exception { + when(deathReportsService.getMdsrRecords(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/death-reports/mdsr/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getMdsrRecords_invalidRequest() throws Exception { + mockMvc.perform(post("/death-reports/mdsr/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getMdsrRecords_exception() throws Exception { + when(deathReportsService.getMdsrRecords(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/death-reports/mdsr/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/iemr/flw/controller/HighRiskControllerTest.java b/src/test/java/com/iemr/flw/controller/HighRiskControllerTest.java new file mode 100644 index 000000000..1576495bb --- /dev/null +++ b/src/test/java/com/iemr/flw/controller/HighRiskControllerTest.java @@ -0,0 +1,439 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.service.HighRiskNonPregnantService; +import com.iemr.flw.service.HighRiskPregnantService; +import com.iemr.flw.service.HighRiskService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class HighRiskControllerTest { + private MockMvc mockMvc; + + @Mock + private HighRiskNonPregnantService highRiskNonPregnantService; + @Mock + private HighRiskPregnantService highRiskPregnantService; + @Mock + private HighRiskService highRiskService; + + @InjectMocks + private HighRiskController controller; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + // Pregnant Assess + @Test + void getAllPregnantAssessByUserId_success() throws Exception { + when(highRiskPregnantService.getAllAssessments(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/pregnant/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void getAllPregnantAssessByUserId_noRecordFound() throws Exception { + when(highRiskPregnantService.getAllAssessments(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/pregnant/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void getAllPregnantAssessByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/pregnant/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void getAllPregnantAssessByUserId_exception() throws Exception { + when(highRiskPregnantService.getAllAssessments(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/pregnant/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllPregnantAssessByUserId_success() throws Exception { + when(highRiskPregnantService.saveAllAssessment(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/pregnant/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllPregnantAssessByUserId_noRecordFound() throws Exception { + when(highRiskPregnantService.saveAllAssessment(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/pregnant/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void saveAllPregnantAssessByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/pregnant/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void saveAllPregnantAssessByUserId_exception() throws Exception { + when(highRiskPregnantService.saveAllAssessment(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/pregnant/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + // Assess + @Test + void getAllAssessByUserId_success() throws Exception { + when(highRiskService.getAllAssessments(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void getAllAssessByUserId_noRecordFound() throws Exception { + when(highRiskService.getAllAssessments(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void getAllAssessByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void getAllAssessByUserId_exception() throws Exception { + when(highRiskService.getAllAssessments(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllAssessByUserId_success() throws Exception { + when(highRiskService.saveAllAssessment(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllAssessByUserId_noRecordFound() throws Exception { + when(highRiskService.saveAllAssessment(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void saveAllAssessByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void saveAllAssessByUserId_exception() throws Exception { + when(highRiskService.saveAllAssessment(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + // Pregnant Track + @Test + void getAllPregnantTrackByUserId_success() throws Exception { + when(highRiskPregnantService.getAllTracking(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/pregnant/track/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void getAllPregnantTrackByUserId_noRecordFound() throws Exception { + when(highRiskPregnantService.getAllTracking(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/pregnant/track/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void getAllPregnantTrackByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/pregnant/track/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void getAllPregnantTrackByUserId_exception() throws Exception { + when(highRiskPregnantService.getAllTracking(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/pregnant/track/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllPregnantTrackByUserId_success() throws Exception { + when(highRiskPregnantService.saveAllTracking(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/pregnant/track/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllPregnantTrackByUserId_noRecordFound() throws Exception { + when(highRiskPregnantService.saveAllTracking(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/pregnant/track/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void saveAllPregnantTrackByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/pregnant/track/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void saveAllPregnantTrackByUserId_exception() throws Exception { + when(highRiskPregnantService.saveAllTracking(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/pregnant/track/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + // NonPregnant Assess + @Test + void getAllNonPregnantAssessByUserId_success() throws Exception { + when(highRiskNonPregnantService.getAllAssessment(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/nonPregnant/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void getAllNonPregnantAssessByUserId_noRecordFound() throws Exception { + when(highRiskNonPregnantService.getAllAssessment(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/nonPregnant/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void getAllNonPregnantAssessByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/nonPregnant/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void getAllNonPregnantAssessByUserId_exception() throws Exception { + when(highRiskNonPregnantService.getAllAssessment(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/nonPregnant/assess/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllNonPregnantAssessByUserId_success() throws Exception { + when(highRiskNonPregnantService.saveAllAssessment(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/nonPregnant/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllNonPregnantAssessByUserId_noRecordFound() throws Exception { + when(highRiskNonPregnantService.saveAllAssessment(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/nonPregnant/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void saveAllNonPregnantAssessByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/nonPregnant/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void saveAllNonPregnantAssessByUserId_exception() throws Exception { + when(highRiskNonPregnantService.saveAllAssessment(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/nonPregnant/assess/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + // NonPregnant Track + @Test + void getAllNonPregnantTrackByUserId_success() throws Exception { + when(highRiskNonPregnantService.getAllTracking(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/nonPregnant/track/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void getAllNonPregnantTrackByUserId_noRecordFound() throws Exception { + when(highRiskNonPregnantService.getAllTracking(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/nonPregnant/track/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void getAllNonPregnantTrackByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/nonPregnant/track/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void getAllNonPregnantTrackByUserId_exception() throws Exception { + when(highRiskNonPregnantService.getAllTracking(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/nonPregnant/track/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllNonPregnantTrackByUserId_success() throws Exception { + when(highRiskNonPregnantService.saveAllTracking(any())).thenReturn("data"); + mockMvc.perform(post("/highRisk/nonPregnant/track/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + @Test + void saveAllNonPregnantTrackByUserId_noRecordFound() throws Exception { + when(highRiskNonPregnantService.saveAllTracking(any())).thenReturn(null); + mockMvc.perform(post("/highRisk/nonPregnant/track/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + @Test + void saveAllNonPregnantTrackByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/highRisk/nonPregnant/track/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void saveAllNonPregnantTrackByUserId_exception() throws Exception { + when(highRiskNonPregnantService.saveAllTracking(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/highRisk/nonPregnant/track/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/iemr/flw/controller/IncentiveControllerTest.java b/src/test/java/com/iemr/flw/controller/IncentiveControllerTest.java new file mode 100644 index 000000000..fffcb9445 --- /dev/null +++ b/src/test/java/com/iemr/flw/controller/IncentiveControllerTest.java @@ -0,0 +1,163 @@ +package com.iemr.flw.controller; + +import com.google.gson.Gson; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.IncentiveActivityDTO; +import com.iemr.flw.dto.iemr.IncentiveRequestDTO; +import com.iemr.flw.service.IncentiveService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import java.util.Collections; +import java.util.List; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class IncentiveControllerTest { + private MockMvc mockMvc; + + @Mock + private IncentiveService incentiveService; + + @InjectMocks + private IncentiveController controller; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void saveIncentiveMasterData_success() throws Exception { + List dtos = Collections.singletonList(new IncentiveActivityDTO()); + when(incentiveService.saveIncentivesMaster(any())).thenReturn("data"); + mockMvc.perform(post("/incentive/masterData/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveIncentiveMasterData_noRecordFound() throws Exception { + List dtos = Collections.singletonList(new IncentiveActivityDTO()); + when(incentiveService.saveIncentivesMaster(any())).thenReturn(null); + mockMvc.perform(post("/incentive/masterData/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveIncentiveMasterData_invalidRequest() throws Exception { + mockMvc.perform(post("/incentive/masterData/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveIncentiveMasterData_exception() throws Exception { + List dtos = Collections.singletonList(new IncentiveActivityDTO()); + when(incentiveService.saveIncentivesMaster(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/incentive/masterData/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveIncentiveMasterData_getAll_success() throws Exception { + IncentiveRequestDTO req = new IncentiveRequestDTO(); + when(incentiveService.getIncentiveMaster(any())).thenReturn("data"); + mockMvc.perform(post("/incentive/masterData/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveIncentiveMasterData_getAll_noRecordFound() throws Exception { + IncentiveRequestDTO req = new IncentiveRequestDTO(); + when(incentiveService.getIncentiveMaster(any())).thenReturn(null); + mockMvc.perform(post("/incentive/masterData/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveIncentiveMasterData_getAll_invalidRequest() throws Exception { + mockMvc.perform(post("/incentive/masterData/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveIncentiveMasterData_getAll_exception() throws Exception { + when(incentiveService.getIncentiveMaster(any())).thenThrow(new RuntimeException("fail")); + IncentiveRequestDTO req = new IncentiveRequestDTO(); + mockMvc.perform(post("/incentive/masterData/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllIncentivesByUserId_success() throws Exception { + GetBenRequestHandler req = new GetBenRequestHandler(); + when(incentiveService.getAllIncentivesByUserId(any())).thenReturn("data"); + mockMvc.perform(post("/incentive/fetchUserData") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllIncentivesByUserId_noRecordFound() throws Exception { + GetBenRequestHandler req = new GetBenRequestHandler(); + when(incentiveService.getAllIncentivesByUserId(any())).thenReturn(null); + mockMvc.perform(post("/incentive/fetchUserData") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllIncentivesByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/incentive/fetchUserData") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getAllIncentivesByUserId_exception() throws Exception { + when(incentiveService.getAllIncentivesByUserId(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/incentive/fetchUserData") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java b/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java index e1a682926..4332eeec0 100644 --- a/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java @@ -1,426 +1,561 @@ -package com.iemr.flw.controller; - +import com.google.gson.Gson; +import com.iemr.flw.controller.MaternalHealthController; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.service.ChildService; import com.iemr.flw.service.DeliveryOutcomeService; import com.iemr.flw.service.InfantService; import com.iemr.flw.service.MaternalHealthService; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import java.util.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; class MaternalHealthControllerTest { - - @InjectMocks - private MaternalHealthController maternalHealthController; + private MockMvc mockMvc; @Mock private MaternalHealthService maternalHealthService; - @Mock private DeliveryOutcomeService deliveryOutcomeService; - @Mock private InfantService infantService; + @Mock + private ChildService childService; + + @InjectMocks + private MaternalHealthController controller; @BeforeEach void setUp() { - MockitoAnnotations.initMocks(this); - } - -// @Test -// void testSavePregnantWomanRegistrations() { -// // Arrange -// List pregnantWomanDTOs = Arrays.asList(new PregnantWomanDTO()); -// -// when(pregnantWomanService.registerPregnantWoman(any())).thenReturn("Save successful"); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.savePregnantWomanRegistrations(pregnantWomanDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals("Save successful", apiResponse.getData()); -// -// verify(pregnantWomanService, times(1)).registerPregnantWoman(pregnantWomanDTOs); -// } -// -// @Test -// void testSavePregnantWomanRegistrations_Exception() { -// // Arrange -// List pregnantWomanDTOs = Arrays.asList(new PregnantWomanDTO()); -// -// when(pregnantWomanService.registerPregnantWoman(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.savePregnantWomanRegistrations(pregnantWomanDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(pregnantWomanService, times(1)).registerPregnantWoman(pregnantWomanDTOs); -// } -// -// @Test -// void testGetPregnantWomanList() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1090); -// -// List responseDTOs = Arrays.asList(new PregnantWomanDTO()); -// when(pregnantWomanService.getPregnantWoman(any())).thenReturn(responseDTOs); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.getPregnantWomanList(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals(responseDTOs, apiResponse.getData()); -// -// verify(pregnantWomanService, times(1)).getPregnantWoman(requestDTO); -// } -// -// @Test -// void testGetPregnantWomanList_Exception() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1090); -// -// when(pregnantWomanService.getPregnantWoman(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.getPregnantWomanList(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(pregnantWomanService, times(1)).getPregnantWoman(requestDTO); -// } -// -// @Test -// void testSaveANCVisit() { -// // Arrange -// List ancVisitDTOs = Arrays.asList(new ANCVisitDTO()); -// -// when(pregnantWomanService.saveANCVisit(any())).thenReturn("Save successful"); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.saveANCVisit(ancVisitDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals("Save successful", apiResponse.getData()); -// -// verify(pregnantWomanService, times(1)).saveANCVisit(ancVisitDTOs); -// } -// -// @Test -// void testSaveANCVisit_Exception() { -// // Arrange -// List ancVisitDTOs = Arrays.asList(new ANCVisitDTO()); -// -// when(pregnantWomanService.saveANCVisit(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.saveANCVisit(ancVisitDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(pregnantWomanService, times(1)).saveANCVisit(ancVisitDTOs); -// } -// -// @Test -// void testGetANCVisitDetails() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1098); -// -// List responseDTOs = Arrays.asList(new ANCVisitDTO()); -// when(pregnantWomanService.getANCVisits(any())).thenReturn(responseDTOs); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.getANCVisitDetails(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals(responseDTOs, apiResponse.getData()); -// -// verify(pregnantWomanService, times(1)).getANCVisits(requestDTO); -// } -// -// @Test -// void testGetANCVisitDetails_Exception() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1098); -// -// when(pregnantWomanService.getANCVisits(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.getANCVisitDetails(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(pregnantWomanService, times(1)).getANCVisits(requestDTO); -// } -// -// @Test -// void testSaveDeliveryOutcome() { -// // Arrange -// List deliveryOutcomeDTOs = Arrays.asList(new DeliveryOutcomeDTO()); -// -// when(deliveryOutcomeService.registerDeliveryOutcome(any())).thenReturn("Save successful"); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.saveDeliveryOutcome(deliveryOutcomeDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals("Save successful", apiResponse.getData()); -// -// verify(deliveryOutcomeService, times(1)).registerDeliveryOutcome(deliveryOutcomeDTOs); -// } -// -// @Test -// void testSaveDeliveryOutcome_Exception() { -// // Arrange -// List deliveryOutcomeDTOs = Arrays.asList(new DeliveryOutcomeDTO()); -// -// when(deliveryOutcomeService.registerDeliveryOutcome(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.saveDeliveryOutcome(deliveryOutcomeDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(deliveryOutcomeService, times(1)).registerDeliveryOutcome(deliveryOutcomeDTOs); -// } -// -// @Test -// void testGetDeliveryOutcome() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1098); -// -// List responseDTOs = Arrays.asList(new DeliveryOutcomeDTO()); -// when(deliveryOutcomeService.getDeliveryOutcome(any())).thenReturn(responseDTOs); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.getDeliveryOutcome(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals(responseDTOs, apiResponse.getData()); -// -// verify(deliveryOutcomeService, times(1)).getDeliveryOutcome(requestDTO); -// } -// -// @Test -// void testGetDeliveryOutcome_Exception() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1098); -// -// when(deliveryOutcomeService.getDeliveryOutcome(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.getDeliveryOutcome(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(deliveryOutcomeService, times(1)).getDeliveryOutcome(requestDTO); -// } -// -// @Test -// void testSaveInfantList() { -// // Arrange -// List infantRegisterDTOs = Arrays.asList(new InfantRegisterDTO()); -// -// when(infantService.registerInfant(any())).thenReturn("Save successful"); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.saveInfantList(infantRegisterDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals("Save successful", apiResponse.getData()); -// -// verify(infantService, times(1)).registerInfant(infantRegisterDTOs); -// } -// -// @Test -// void testSaveInfantList_Exception() { -// // Arrange -// List infantRegisterDTOs = Arrays.asList(new InfantRegisterDTO()); -// -// when(infantService.registerInfant(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.saveInfantList(infantRegisterDTOs, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(infantService, times(1)).registerInfant(infantRegisterDTOs); -// } -// -// @Test -// void testGetInfantList() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1098); -// -// List responseDTOs = Arrays.asList(new InfantRegisterDTO()); -// when(infantService.getInfantDetails(any())).thenReturn(responseDTOs); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.getInfantList(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertTrue(apiResponse.getSuccess()); -// assertNull(apiResponse.getMessage()); -// -// assertEquals(responseDTOs, apiResponse.getData()); -// -// verify(infantService, times(1)).getInfantDetails(requestDTO); -// } -// -// @Test -// void testGetInfantList_Exception() { -// // Arrange -// GetBenRequestHandler requestDTO = new GetBenRequestHandler(); -// requestDTO.setAshaId(1098); -// -// when(infantService.getInfantDetails(any())).thenThrow(new RuntimeException("Test exception")); -// -// // Act -// ResponseEntity responseEntity = maternalHealthController.getInfantList(requestDTO, "AuthorizationToken"); -// -// // Assert -// assertNotNull(responseEntity); -// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); -// -// ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); -// assertNotNull(apiResponse); -// assertFalse(apiResponse.getSuccess()); -// assertNotNull(apiResponse.getMessage()); -// -// assertNull(apiResponse.getData()); -// -// verify(infantService, times(1)).getInfantDetails(requestDTO); -// } + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void savePregnantWomanRegistrations_success() throws Exception { + List dtos = Collections.singletonList(new PregnantWomanDTO()); + when(maternalHealthService.registerPregnantWoman(any())).thenReturn("success"); + mockMvc.perform(post("/maternalCare/pregnantWoman/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void savePregnantWomanRegistrations_invalidRequest() throws Exception { + List dtos = Collections.emptyList(); + mockMvc.perform(post("/maternalCare/pregnantWoman/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getPregnantWomanList_success() throws Exception { + when(maternalHealthService.getPregnantWoman(any())).thenReturn(Collections.singletonList(new PregnantWomanDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pregnantWoman/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getPregnantWomanList_invalidRequest() throws Exception { + mockMvc.perform(post("/maternalCare/pregnantWoman/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getPregnantWomanList_noRecordFound() throws Exception { + when(maternalHealthService.getPregnantWoman(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pregnantWoman/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveANCVisit_success() throws Exception { + List dtos = Collections.singletonList(new ANCVisitDTO()); + when(maternalHealthService.saveANCVisit(any())).thenReturn("success"); + mockMvc.perform(post("/maternalCare/ancVisit/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveANCVisit_invalidRequest() throws Exception { + List dtos = Collections.emptyList(); + mockMvc.perform(post("/maternalCare/ancVisit/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getANCVisitDetails_success() throws Exception { + when(maternalHealthService.getANCVisits(any())).thenReturn(Collections.singletonList(new ANCVisitDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/ancVisit/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getANCVisitDetails_invalidRequest() throws Exception { + mockMvc.perform(post("/maternalCare/ancVisit/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getANCVisitDetails_noRecordFound() throws Exception { + when(maternalHealthService.getANCVisits(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/ancVisit/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveDeliveryOutcome_success() throws Exception { + List dtos = Collections.singletonList(new DeliveryOutcomeDTO()); + when(deliveryOutcomeService.registerDeliveryOutcome(any())).thenReturn("success"); + mockMvc.perform(post("/maternalCare/deliveryOutcome/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveDeliveryOutcome_invalidRequest() throws Exception { + List dtos = Collections.emptyList(); + mockMvc.perform(post("/maternalCare/deliveryOutcome/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getDeliveryOutcome_success() throws Exception { + when(deliveryOutcomeService.getDeliveryOutcome(any())).thenReturn(Collections.singletonList(new DeliveryOutcomeDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/deliveryOutcome/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getDeliveryOutcome_invalidRequest() throws Exception { + mockMvc.perform(post("/maternalCare/deliveryOutcome/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getDeliveryOutcome_noRecordFound() throws Exception { + when(deliveryOutcomeService.getDeliveryOutcome(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/deliveryOutcome/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveInfantList_success() throws Exception { + List dtos = Collections.singletonList(new InfantRegisterDTO()); + when(infantService.registerInfant(any())).thenReturn("success"); + mockMvc.perform(post("/maternalCare/infant/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveInfantList_invalidRequest() throws Exception { + List dtos = Collections.emptyList(); + mockMvc.perform(post("/maternalCare/infant/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getInfantList_success() throws Exception { + when(infantService.getInfantDetails(any())).thenReturn(Collections.singletonList(new InfantRegisterDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/infant/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getInfantList_invalidRequest() throws Exception { + mockMvc.perform(post("/maternalCare/infant/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getInfantList_noRecordFound() throws Exception { + when(infantService.getInfantDetails(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/infant/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllChildRegisterDetails_success() throws Exception { + when(childService.getByUserId(any())).thenReturn("child"); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/child/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllChildRegisterDetails_invalidRequest() throws Exception { + mockMvc.perform(post("/maternalCare/child/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + @Test + void getAllChildRegisterDetails_noRecordFound() throws Exception { + when(childService.getByUserId(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/child/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveAllChildDetails_success() throws Exception { + List dtos = Collections.singletonList(new ChildRegisterDTO()); + when(childService.save(any())).thenReturn("success"); + mockMvc.perform(post("/maternalCare/child/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveAllChildDetails_invalidRequest() throws Exception { + List dtos = Collections.emptyList(); + mockMvc.perform(post("/maternalCare/child/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getAllPmsmaDetails_success() throws Exception { + when(maternalHealthService.getPmsmaRecords(any())).thenReturn(Collections.singletonList(new PmsmaDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pmsma/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllPmsmaDetails_invalidRequest() throws Exception { + mockMvc.perform(post("/maternalCare/pmsma/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getAllPmsmaDetails_noRecordFound() throws Exception { + when(maternalHealthService.getPmsmaRecords(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pmsma/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveAllPmsmaRecords_success() throws Exception { + List dtos = Collections.singletonList(new PmsmaDTO()); + when(maternalHealthService.savePmsmaRecords(any())).thenReturn("success"); + mockMvc.perform(post("/maternalCare/pmsma/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void saveAllPmsmaRecords_invalidRequest() throws Exception { + List dtos = Collections.emptyList(); + mockMvc.perform(post("/maternalCare/pmsma/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void savePNCVisit_success() throws Exception { + List dtos = Collections.singletonList(new PNCVisitDTO()); + when(maternalHealthService.savePNCVisit(any())).thenReturn("success"); + mockMvc.perform(post("/maternalCare/pnc/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void savePNCVisit_invalidRequest() throws Exception { + List dtos = Collections.emptyList(); + mockMvc.perform(post("/maternalCare/pnc/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getPNCVisitDetails_success() throws Exception { + when(maternalHealthService.getPNCVisits(any())).thenReturn(Collections.singletonList(new PNCVisitDTO())); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pnc/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getPNCVisitDetails_invalidRequest() throws Exception { + mockMvc.perform(post("/maternalCare/pnc/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getPNCVisitDetails_noRecordFound() throws Exception { + when(maternalHealthService.getPNCVisits(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pnc/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void savePregnantWomanRegistrations_exception() throws Exception { + List dtos = Collections.singletonList(new PregnantWomanDTO()); + when(maternalHealthService.registerPregnantWoman(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/maternalCare/pregnantWoman/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getPregnantWomanList_exception() throws Exception { + when(maternalHealthService.getPregnantWoman(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pregnantWoman/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveANCVisit_exception() throws Exception { + List dtos = Collections.singletonList(new ANCVisitDTO()); + when(maternalHealthService.saveANCVisit(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/maternalCare/ancVisit/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getANCVisitDetails_exception() throws Exception { + when(maternalHealthService.getANCVisits(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/ancVisit/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveDeliveryOutcome_exception() throws Exception { + List dtos = Collections.singletonList(new DeliveryOutcomeDTO()); + when(deliveryOutcomeService.registerDeliveryOutcome(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/maternalCare/deliveryOutcome/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getDeliveryOutcome_exception() throws Exception { + when(deliveryOutcomeService.getDeliveryOutcome(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/deliveryOutcome/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveInfantList_exception() throws Exception { + List dtos = Collections.singletonList(new InfantRegisterDTO()); + when(infantService.registerInfant(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/maternalCare/infant/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getInfantList_exception() throws Exception { + when(infantService.getInfantDetails(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/infant/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void getAllChildRegisterDetails_exception() throws Exception { + when(childService.getByUserId(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/child/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveAllChildDetails_exception() throws Exception { + List dtos = Collections.singletonList(new ChildRegisterDTO()); + when(childService.save(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/maternalCare/child/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getAllPmsmaDetails_exception() throws Exception { + when(maternalHealthService.getPmsmaRecords(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pmsma/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } + + @Test + void saveAllPmsmaRecords_exception() throws Exception { + List dtos = Collections.singletonList(new PmsmaDTO()); + when(maternalHealthService.savePmsmaRecords(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/maternalCare/pmsma/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void savePNCVisit_exception() throws Exception { + List dtos = Collections.singletonList(new PNCVisitDTO()); + when(maternalHealthService.savePNCVisit(any())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(post("/maternalCare/pnc/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(dtos))) + .andExpect(status().isOk()); + } + + @Test + void getPNCVisitDetails_exception() throws Exception { + when(maternalHealthService.getPNCVisits(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/maternalCare/pnc/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content(new Gson().toJson(req))) + .andExpect(status().isOk()); + } } diff --git a/src/test/java/com/iemr/flw/controller/TBControllerTest.java b/src/test/java/com/iemr/flw/controller/TBControllerTest.java new file mode 100644 index 000000000..212cdbeb7 --- /dev/null +++ b/src/test/java/com/iemr/flw/controller/TBControllerTest.java @@ -0,0 +1,222 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.TBScreeningRequestDTO; +import com.iemr.flw.dto.iemr.TBSuspectedRequestDTO; +import com.iemr.flw.service.TBScreeningService; +import com.iemr.flw.service.TBSuspectedService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import java.util.Collections; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class TBControllerTest { + private MockMvc mockMvc; + + @Mock + private TBScreeningService tbScreeningService; + @Mock + private TBSuspectedService tbSuspectedService; + + @InjectMocks + private TBController controller; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void getAllScreeningByUserId_success() throws Exception { + when(tbScreeningService.getByUserId(any())).thenReturn("data"); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/tb/screening/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void getAllScreeningByUserId_noRecordFound() throws Exception { + when(tbScreeningService.getByUserId(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/tb/screening/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + + @Test + void getAllScreeningByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/tb/screening/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getAllScreeningByUserId_exception() throws Exception { + when(tbScreeningService.getByUserId(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/tb/screening/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void saveAllScreeningByUserId_success() throws Exception { + when(tbScreeningService.save(any())).thenReturn("data"); + TBScreeningRequestDTO req = new TBScreeningRequestDTO(); + mockMvc.perform(post("/tb/screening/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void saveAllScreeningByUserId_noRecordFound() throws Exception { + when(tbScreeningService.save(any())).thenReturn(null); + TBScreeningRequestDTO req = new TBScreeningRequestDTO(); + mockMvc.perform(post("/tb/screening/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + + @Test + void saveAllScreeningByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/tb/screening/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveAllScreeningByUserId_exception() throws Exception { + when(tbScreeningService.save(any())).thenThrow(new RuntimeException("fail")); + TBScreeningRequestDTO req = new TBScreeningRequestDTO(); + mockMvc.perform(post("/tb/screening/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void getAllSuspectedByUserId_success() throws Exception { + when(tbSuspectedService.getByUserId(any())).thenReturn("data"); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/tb/suspected/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void getAllSuspectedByUserId_noRecordFound() throws Exception { + when(tbSuspectedService.getByUserId(any())).thenReturn(null); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/tb/suspected/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + + @Test + void getAllSuspectedByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/tb/suspected/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void getAllSuspectedByUserId_exception() throws Exception { + when(tbSuspectedService.getByUserId(any())).thenThrow(new RuntimeException("fail")); + GetBenRequestHandler req = new GetBenRequestHandler(); + mockMvc.perform(post("/tb/suspected/getAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void saveAllSuspectedByUserId_success() throws Exception { + when(tbSuspectedService.save(any())).thenReturn("data"); + TBSuspectedRequestDTO req = new TBSuspectedRequestDTO(); + mockMvc.perform(post("/tb/suspected/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } + + @Test + void saveAllSuspectedByUserId_noRecordFound() throws Exception { + when(tbSuspectedService.save(any())).thenReturn(null); + TBSuspectedRequestDTO req = new TBSuspectedRequestDTO(); + mockMvc.perform(post("/tb/suspected/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()) + .andExpect(result -> { + String content = result.getResponse().getContentAsString(); + assert content.contains("No record found"); + }); + } + + @Test + void saveAllSuspectedByUserId_invalidRequest() throws Exception { + mockMvc.perform(post("/tb/suspected/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("null")) + .andExpect(status().isBadRequest()); + } + + @Test + void saveAllSuspectedByUserId_exception() throws Exception { + when(tbSuspectedService.save(any())).thenThrow(new RuntimeException("fail")); + TBSuspectedRequestDTO req = new TBSuspectedRequestDTO(); + mockMvc.perform(post("/tb/suspected/saveAll") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer token") + .content("{}")) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/iemr/flw/controller/UserControllerTest.java b/src/test/java/com/iemr/flw/controller/UserControllerTest.java index c280ca12f..af339918f 100644 --- a/src/test/java/com/iemr/flw/controller/UserControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/UserControllerTest.java @@ -8,72 +8,50 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; class UserControllerTest { + private MockMvc mockMvc; @Mock private UserService userService; @InjectMocks - private UserController userController; + private UserController controller; @BeforeEach void setUp() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } @Test - void testGetUserDetail_Success() { - // Arrange - Integer userId = 123; - UserServiceRoleDTO userServiceRoleDTO = new UserServiceRoleDTO(); - userServiceRoleDTO.setUserId(userId); - - when(userService.getUserDetail(anyInt())).thenReturn(userServiceRoleDTO); - - // Act - ResponseEntity responseEntity = userController.getUserDetail(userId, "AuthorizationToken"); - - // Assert - assertNotNull(responseEntity); - assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); - - ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); - assertNotNull(apiResponse); - assertTrue(apiResponse.getSuccess()); - assertNull(apiResponse.getMessage()); - - assertEquals(userServiceRoleDTO, apiResponse.getData()); - - verify(userService, times(1)).getUserDetail(userId); + void getUserDetail_success() throws Exception { + UserServiceRoleDTO dto = new UserServiceRoleDTO(); + when(userService.getUserDetail(anyInt())).thenReturn(dto); + mockMvc.perform(get("/user/getUserDetail") + .param("userId", "1") + .header("Authorization", "Bearer token") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isAccepted()) + .andExpect(jsonPath("$.success").value(true)); } @Test - void testGetUserDetail_Exception() { - // Arrange - Integer userId = 123; - - when(userService.getUserDetail(anyInt())).thenThrow(new RuntimeException("Test exception")); - - // Act - ResponseEntity responseEntity = userController.getUserDetail(userId, "AuthorizationToken"); - - // Assert - assertNotNull(responseEntity); - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); - - ApiResponse apiResponse = (ApiResponse) responseEntity.getBody(); - assertNotNull(apiResponse); - assertFalse(apiResponse.getSuccess()); - assertNotNull(apiResponse.getMessage()); - - assertNull(apiResponse.getData()); - - verify(userService, times(1)).getUserDetail(userId); + void getUserDetail_exception() throws Exception { + when(userService.getUserDetail(anyInt())).thenThrow(new RuntimeException("fail")); + mockMvc.perform(get("/user/getUserDetail") + .param("userId", "1") + .header("Authorization", "Bearer token") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isInternalServerError()) + .andExpect(jsonPath("$.success").value(false)); } } diff --git a/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java deleted file mode 100644 index c948d2f98..000000000 --- a/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.iemr.flw.service.impl; - -import com.iemr.flw.domain.iemr.EligibleCoupleRegister; -import com.iemr.flw.domain.iemr.EligibleCoupleTracking; -import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.EligibleCoupleDTO; -import com.iemr.flw.dto.iemr.EligibleCoupleTrackingDTO; -import com.iemr.flw.repo.iemr.EligibleCoupleRegisterRepo; -import com.iemr.flw.repo.iemr.EligibleCoupleTrackingRepo; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -class CoupleServiceImplTest { - - @Mock - private EligibleCoupleRegisterRepo eligibleCoupleRegisterRepo; - - @Mock - private EligibleCoupleTrackingRepo eligibleCoupleTrackingRepo; - - @InjectMocks - private CoupleServiceImpl coupleService; - - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); - } - -// @Test -// void testRegisterEligibleCouple_Success() { -// // Arrange -// List eligibleCoupleDTOs = new ArrayList<>(); -// eligibleCoupleDTOs.add(new EligibleCoupleDTO()); -// -// EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); -// when(eligibleCoupleRegisterRepo.getECRWithBen(anyLong())).thenReturn(existingECR); -// -// // Act -// String result = coupleService.registerEligibleCouple(eligibleCoupleDTOs); -// -// // Assert -// assertNotNull(result); -// assertTrue(result.contains("already exists")); -// -// verify(eligibleCoupleRegisterRepo, times(1)).getECRWithBen(anyLong()); -// verify(eligibleCoupleRegisterRepo, never()).save(anyList()); -// } -// -// @Test -// void testRegisterEligibleCouple_Success_NewECR() { -// // Arrange -// List eligibleCoupleDTOs = new ArrayList<>(); -// eligibleCoupleDTOs.add(new EligibleCoupleDTO()); -// -// when(eligibleCoupleRegisterRepo.getECRWithBen(anyLong())).thenReturn(null); -// -// // Act -// String result = coupleService.registerEligibleCouple(eligibleCoupleDTOs); -// -// // Assert -// assertNotNull(result); -// assertTrue(result.contains("Eligible Couple Register Details Saved!")); -// -// verify(eligibleCoupleRegisterRepo, times(1)).getECRWithBen(anyLong()); -// verify(eligibleCoupleRegisterRepo, times(1)).save(anyList()); -// } -// -// @Test -// void testRegisterEligibleCoupleTracking_Success() { -// // Arrange -// List eligibleCoupleTrackingDTOs = new ArrayList<>(); -// eligibleCoupleTrackingDTOs.add(new EligibleCoupleTrackingDTO()); -// -// // Act -// String result = coupleService.registerEligibleCoupleTracking(eligibleCoupleTrackingDTOs); -// -// // Assert -// assertNotNull(result); -// assertEquals("saved successfully", result); -// -// verify(eligibleCoupleTrackingRepo, times(1)).save(anyList()); -// } -// -// @Test -// void testGetEligibleCoupleRegRecords_Success() { -// // Arrange -// GetBenRequestHandler dto = new GetBenRequestHandler(); -// dto.setAshaId(123); -// dto.setFromDate(new Timestamp((new Date()).getTime())); -// dto.setToDate(new Timestamp((new Date()).getTime())); -// -// List eligibleCoupleRegisterList = new ArrayList<>(); -// eligibleCoupleRegisterList.add(new EligibleCoupleRegister()); -// -// when(eligibleCoupleRegisterRepo.getECRegRecords(dto.getAshaId(), dto.getFromDate(), dto.getToDate())).thenReturn(eligibleCoupleRegisterList); -// -// // Act -// List result = coupleService.getEligibleCoupleRegRecords(dto); -// -// // Assert -// assertNotNull(result); -// assertEquals(eligibleCoupleRegisterList.size(), result.size()); -// -// verify(eligibleCoupleRegisterRepo, times(1)).getECRegRecords(dto.getAshaId(), dto.getFromDate(), dto.getToDate()); -// } -// -// @Test -// void testGetEligibleCoupleTracking_Success() { -// // Arrange -// GetBenRequestHandler dto = new GetBenRequestHandler(); -// dto.setAshaId(123); -// dto.setFromDate(new Timestamp((new Date()).getTime())); -// dto.setToDate(new Timestamp((new Date()).getTime())); -// -// List eligibleCoupleTrackingList = new ArrayList<>(); -// eligibleCoupleTrackingList.add(new EligibleCoupleTracking()); -// -// when(eligibleCoupleTrackingRepo.getECTrackRecords(dto.getAshaId(), dto.getFromDate(), dto.getToDate())).thenReturn(eligibleCoupleTrackingList); -// -// // Act -// List result = coupleService.getEligibleCoupleTracking(dto); -// -// // Assert -// assertNotNull(result); -// assertEquals(eligibleCoupleTrackingList.size(), result.size()); -// -// verify(eligibleCoupleTrackingRepo, times(1)).getECTrackRecords(dto.getAshaId(), dto.getFromDate(), dto.getToDate()); -// } -} - - diff --git a/src/test/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImplTest.java deleted file mode 100644 index 8cc14ab08..000000000 --- a/src/test/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImplTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.iemr.flw.service.impl; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.iemr.flw.domain.iemr.DeliveryOutcome; -import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.DeliveryOutcomeDTO; -import com.iemr.flw.repo.iemr.DeliveryOutcomeRepo; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -class DeliveryOutcomeServiceImplTest { - - @Mock - private DeliveryOutcomeRepo deliveryOutcomeRepo; - - @InjectMocks - private DeliveryOutcomeServiceImpl deliveryOutcomeService; - - private ObjectMapper mapper = new ObjectMapper(); - - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); - } - -// @Test -// void testRegisterDeliveryOutcome_Success() { -// // Arrange -// List deliveryOutcomeDTOs = new ArrayList<>(); -// deliveryOutcomeDTOs.add(new DeliveryOutcomeDTO()); -// -// // Act -// String result = deliveryOutcomeService.registerDeliveryOutcome(deliveryOutcomeDTOs); -// -// // Assert -// assertNotNull(result); -// assertEquals("saved successfully", result); -// -// verify(deliveryOutcomeRepo, times(1)).save(anyList()); -// } -// -// @Test -// void testGetDeliveryOutcome_Success() { -// // Arrange -// GetBenRequestHandler dto = new GetBenRequestHandler(); -// dto.setAshaId(123); -// dto.setFromDate(new Timestamp((new Date()).getTime())); -// dto.setToDate(new Timestamp((new Date()).getTime())); -// -// List deliveryOutcomeList = new ArrayList<>(); -// deliveryOutcomeList.add(new DeliveryOutcome()); -// -// when(deliveryOutcomeRepo.getDeliveryOutcomeByBenId(dto.getAshaId(), dto.getFromDate(), dto.getToDate())).thenReturn(deliveryOutcomeList); -// -// // Act -// List result = deliveryOutcomeService.getDeliveryOutcome(dto); -// -// // Assert -// assertNotNull(result); -// assertEquals(deliveryOutcomeList.size(), result.size()); -// -// verify(deliveryOutcomeRepo, times(1)).getDeliveryOutcomeByBenId(dto.getAshaId(), dto.getFromDate(), dto.getToDate()); -// } -} diff --git a/src/test/java/com/iemr/flw/service/impl/InfantServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/InfantServiceImplTest.java deleted file mode 100644 index 04fac23e6..000000000 --- a/src/test/java/com/iemr/flw/service/impl/InfantServiceImplTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.iemr.flw.service.impl; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.iemr.flw.domain.iemr.InfantRegister; -import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.InfantRegisterDTO; -import com.iemr.flw.repo.iemr.InfantRegisterRepo; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -class InfantServiceImplTest { - - @Mock - private InfantRegisterRepo infantRegisterRepo; - - @InjectMocks - private InfantServiceImpl infantService; - - private ObjectMapper mapper = new ObjectMapper(); - - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); - } - -// @Test -// void testRegisterInfant_Success() { -// // Arrange -// List infantRegisterDTOs = new ArrayList<>(); -// infantRegisterDTOs.add(new InfantRegisterDTO()); -// -// // Act -// String result = infantService.registerInfant(infantRegisterDTOs); -// -// // Assert -// assertNotNull(result); -// assertEquals("saved successfully", result); -// -// verify(infantRegisterRepo, times(1)).save(anyList()); -// } -// -// @Test -// void testGetInfantDetails_Success() { -// // Arrange -// GetBenRequestHandler dto = new GetBenRequestHandler(); -// dto.setAshaId(123); -// dto.setFromDate(new Timestamp((new Date()).getTime())); -// dto.setToDate(new Timestamp((new Date()).getTime())); -// -// List infantRegisterList = new ArrayList<>(); -// infantRegisterList.add(new InfantRegister()); -// -// when(infantRegisterRepo.getInfantDetailsForUser(dto.getAshaId(), dto.getFromDate(), dto.getToDate())).thenReturn(infantRegisterList); -// -// // Act -// List result = infantService.getInfantDetails(dto); -// -// // Assert -// assertNotNull(result); -// assertEquals(infantRegisterList.size(), result.size()); -// -// verify(infantRegisterRepo, times(1)).getInfantDetailsForUser(dto.getAshaId(), dto.getFromDate(), dto.getToDate()); -// } -} diff --git a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java deleted file mode 100644 index fb37252c6..000000000 --- a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.iemr.flw.service.impl; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.iemr.flw.repo.iemr.ANCVisitRepo; -import com.iemr.flw.repo.iemr.PregnantWomanRegisterRepo; -import org.junit.jupiter.api.BeforeEach; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -class MaternalHealthServiceImplTest { - - @Mock - private PregnantWomanRegisterRepo pregnantWomanRegisterRepo; - - @Mock - private ANCVisitRepo ancVisitRepo; - - @InjectMocks - private MaternalHealthServiceImpl pregnantWomanService; - - private ObjectMapper mapper = new ObjectMapper(); - - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); - } - -// @Test -// void testRegisterPregnantWoman_Success() { -// // Arrange -// List pregnantWomanDTOs = new ArrayList<>(); -// pregnantWomanDTOs.add(new PregnantWomanDTO()); -// -// // Act -// String result = pregnantWomanService.registerPregnantWoman(pregnantWomanDTOs); -// -// // Assert -// assertNotNull(result); -// assertEquals("saved successfully", result); -// -// verify(pregnantWomanRegisterRepo, times(1)).save(anyList()); -// } -// -// @Test -// void testGetPregnantWoman_Success() { -// // Arrange -// GetBenRequestHandler dto = new GetBenRequestHandler(); -// dto.setAshaId(123); -// dto.setFromDate(new Timestamp((new Date()).getTime())); -// dto.setToDate(new Timestamp((new Date()).getTime())); -// -// List pregnantWomanRegisterList = new ArrayList<>(); -// pregnantWomanRegisterList.add(new PregnantWomanRegister()); -// -// when(pregnantWomanRegisterRepo.getPWRWithBen(dto.getAshaId(), dto.getFromDate(), dto.getToDate())).thenReturn(pregnantWomanRegisterList); -// -// // Act -// List result = pregnantWomanService.getPregnantWoman(dto); -// -// // Assert -// assertNotNull(result); -// assertEquals(pregnantWomanRegisterList.size(), result.size()); -// -// verify(pregnantWomanRegisterRepo, times(1)).getPWRWithBen(dto.getAshaId(), dto.getFromDate(), dto.getToDate()); -// } -// -// @Test -// void testGetANCVisits_Success() { -// // Arrange -// GetBenRequestHandler dto = new GetBenRequestHandler(); -// dto.setAshaId(123); -// dto.setFromDate(new Timestamp((new Date()).getTime())); -// dto.setToDate(new Timestamp((new Date()).getTime())); -// -// List ancVisits = new ArrayList<>(); -// ancVisits.add(new ANCVisit()); -// -// when(ancVisitRepo.getANCForPW(dto.getAshaId(), dto.getFromDate(), dto.getToDate())).thenReturn(ancVisits); -// -// // Act -// List result = pregnantWomanService.getANCVisits(dto); -// -// // Assert -// assertNotNull(result); -// assertEquals(ancVisits.size(), result.size()); -// -// verify(ancVisitRepo, times(1)).getANCForPW(dto.getAshaId(), dto.getFromDate(), dto.getToDate()); -// } -// -// @Test -// void testSaveANCVisit_Success() { -// // Arrange -// List ancVisitDTOs = new ArrayList<>(); -// ancVisitDTOs.add(new ANCVisitDTO()); -// -// // Act -// String result = pregnantWomanService.saveANCVisit(ancVisitDTOs); -// -// // Assert -// assertNotNull(result); -// assertEquals("saved successfully", result); -// -// verify(ancVisitRepo, times(1)).save(anyList()); -// } -} diff --git a/src/test/java/com/iemr/flw/service/impl/UserServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/UserServiceImplTest.java deleted file mode 100644 index 8d204e40c..000000000 --- a/src/test/java/com/iemr/flw/service/impl/UserServiceImplTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.iemr.flw.service.impl; - -import com.iemr.flw.dto.iemr.UserServiceRoleDTO; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.when; - -class UserServiceImplTest { - - @Mock - private UserServiceRoleRepo userServiceRoleRepo; - - @InjectMocks - private UserServiceImpl userService; - - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); - } - - @Test - void testGetUserDetail_Success() { - // Arrange - int userId = 123; - UserServiceRoleDTO expectedUserRoleDTO = new UserServiceRoleDTO(); - expectedUserRoleDTO.setUserId(userId); - expectedUserRoleDTO.setRoleName("ROLE_USER"); - - List userRoleList = new ArrayList<>(); - userRoleList.add(expectedUserRoleDTO); - - when(userServiceRoleRepo.getUserRole(anyInt())).thenReturn(userRoleList); - - // Act - UserServiceRoleDTO result = userService.getUserDetail(userId); - - // Assert - assertEquals(expectedUserRoleDTO.getUserId(), result.getUserId()); - assertEquals(expectedUserRoleDTO.getRoleName(), result.getRoleName()); - } -} From bf5306f7d2b512bcc05c247e5469603030a61593 Mon Sep 17 00:00:00 2001 From: Zapper9982 Date: Sat, 16 Aug 2025 21:08:13 +0530 Subject: [PATCH 002/237] test(Services): Complete testcases for Services of FLW --- .../MaternalHealthControllerTest.java | 2 + .../impl/BeneficiaryServiceImplTest.java | 773 ++++++++++++++++++ .../flw/service/impl/CbacServiceImplTest.java | 142 ++++ .../impl/ChildCareServiceImplTest.java | 745 +++++++++++++++++ .../service/impl/ChildServiceImplTest.java | 110 +++ .../service/impl/CoupleServiceImplTest.java | 685 ++++++++++++++++ .../impl/DeathReportsServiceImplTest.java | 164 ++++ .../impl/DeliveryOutcomeServiceImplTest.java | 91 +++ .../impl/HRNonPregnantServiceImplTest.java | 197 +++++ .../impl/HRPregnantServiceImplTest.java | 190 +++++ .../service/impl/HighRiskServiceImplTest.java | 114 +++ .../impl/IncentiveServiceImplTest.java | 128 +++ .../service/impl/InfantServiceImplTest.java | 101 +++ .../impl/MaternalHealthServiceImplTest.java | 632 ++++++++++++++ .../impl/TBScreeningServiceImplTest.java | 118 +++ .../impl/TBSuspectedServiceImplTest.java | 91 +++ .../flw/service/impl/UserServiceImplTest.java | 41 + 17 files changed, 4324 insertions(+) create mode 100644 src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/CbacServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/ChildServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/HRNonPregnantServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/HRPregnantServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/HighRiskServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/IncentiveServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/InfantServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/TBSuspectedServiceImplTest.java create mode 100644 src/test/java/com/iemr/flw/service/impl/UserServiceImplTest.java diff --git a/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java b/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java index 4332eeec0..72e56a67a 100644 --- a/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java @@ -1,3 +1,5 @@ +package com.iemr.flw.controller; + import com.google.gson.Gson; import com.iemr.flw.controller.MaternalHealthController; import com.iemr.flw.dto.identity.GetBenRequestHandler; diff --git a/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java new file mode 100644 index 000000000..1d4aedda5 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java @@ -0,0 +1,773 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.identity.*; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.identity.HouseHoldRepo; +import com.iemr.flw.utils.config.ConfigProperties; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.test.util.ReflectionTestUtils; + +import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class BeneficiaryServiceImplTest { + + @Mock + private BeneficiaryRepo beneficiaryRepo; + + @Mock + private HouseHoldRepo houseHoldRepo; + + @InjectMocks + private BeneficiaryServiceImpl service; + + private GetBenRequestHandler request; + private RMNCHMBeneficiaryaddress address; + private RMNCHMBeneficiarymapping mapping; + private final String authorization = "Bearer test-token"; + private final Timestamp currentTime = new Timestamp(System.currentTimeMillis()); + + @BeforeEach + void setUp() { + // Set the property value for page size + ReflectionTestUtils.setField(service, "door_to_door_page_size", "10"); + + // Setup common test data + request = new GetBenRequestHandler(); + request.setAshaId(1); + request.setPageNo(0); + request.setUserName("testUser"); + + address = createTestAddress(); + mapping = createTestMapping(); + } + + // getBenData tests + @Test + void testGetBenData_withValidRequest_success() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + setupMappingDataMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("\"data\"")); + assertTrue(result.contains("\"pageSize\":10")); + assertTrue(result.contains("\"totalPage\":1")); + + // Verify repository calls + verify(beneficiaryRepo).getUserName(request.getAshaId()); + verify(beneficiaryRepo).getBenDataByUser("testUser", pageRequest); + verify(beneficiaryRepo).getByAddressID(address.getId()); + } + + @Test + void testGetBenData_withDateRange_success() throws Exception { + // Arrange + Timestamp fromDate = Timestamp.valueOf(LocalDate.now().minusDays(7).atStartOfDay()); + Timestamp toDate = Timestamp.valueOf(LocalDate.now().atStartOfDay()); + request.setFromDate(fromDate); + request.setToDate(toDate); + + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataWithinDates("testUser", fromDate, toDate, pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + setupMappingDataMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("\"data\"")); + + // Verify repository calls + verify(beneficiaryRepo).getUserName(request.getAshaId()); + verify(beneficiaryRepo).getBenDataWithinDates("testUser", fromDate, toDate, pageRequest); + } + + @Test + void testGetBenData_nullAshaId_throwsException() { + // Arrange + request.setAshaId(null); + + // Act & Assert + Exception exception = assertThrows(Exception.class, () -> { + service.getBenData(request, authorization); + }); + assertEquals("Invalid/missing village details", exception.getMessage()); + } + + @Test + void testGetBenData_invalidPageNo_throwsException() { + // Arrange + request.setPageNo(null); + + // Act & Assert + Exception exception = assertThrows(Exception.class, () -> { + service.getBenData(request, authorization); + }); + assertEquals("Invalid page no", exception.getMessage()); + } + + @Test + void testGetBenData_userNameNotFound_throwsException() { + // Arrange + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn(null); + + // Act & Assert + Exception exception = assertThrows(Exception.class, () -> { + service.getBenData(request, authorization); + }); + assertEquals("Asha details not found, please contact administrator", exception.getMessage()); + + verify(beneficiaryRepo).getUserName(request.getAshaId()); + } + + @Test + void testGetBenData_emptyUserName_throwsException() { + // Arrange + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn(""); + + // Act & Assert + Exception exception = assertThrows(Exception.class, () -> { + service.getBenData(request, authorization); + }); + assertEquals("Asha details not found, please contact administrator", exception.getMessage()); + } + + @Test + void testGetBenData_noResultsFound_returnsNull() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List emptyList = new ArrayList<>(); + Page emptyPage = new PageImpl<>(emptyList, pageRequest, 0); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(emptyPage); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNull(result); + } + + @Test + void testGetBenData_repositoryException_throwsException() { + // Arrange + when(beneficiaryRepo.getUserName(request.getAshaId())).thenThrow(new RuntimeException("Database error")); + + // Act & Assert + Exception exception = assertThrows(Exception.class, () -> { + service.getBenData(request, authorization); + }); + assertEquals("Database error", exception.getMessage()); + } + + @Test + void testGetBenData_nullMapping_skipsProcessing() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(null); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("\"data\":[]")); + verify(beneficiaryRepo).getByAddressID(address.getId()); + } + + @Test + void testGetBenData_withCompleteMapping_success() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + setupCompleteEntityMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("\"beneficiaryDetails\"")); + assertTrue(result.contains("\"householdDetails\"")); + assertTrue(result.contains("\"bornbirthDeatils\"")); + + // Verify all entity retrievals + verify(beneficiaryRepo).getDetailsById(mapping.getBenDetailsId()); + verify(beneficiaryRepo).getAccountById(mapping.getBenAccountID()); + verify(beneficiaryRepo).getImageById(mapping.getBenImageId().longValue()); + verify(beneficiaryRepo).getAddressById(mapping.getBenAddressId()); + verify(beneficiaryRepo).getContactById(mapping.getBenContactsId()); + } + + @Test + void testGetBenData_ageCalculation_years() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + // Create detail with DOB 25 years ago + RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); + LocalDate birthDate = LocalDate.now().minusYears(25).minusMonths(3); + detail.setDob(Timestamp.valueOf(birthDate.atStartOfDay())); + + when(beneficiaryRepo.getDetailsById(mapping.getBenDetailsId())).thenReturn(detail); + setupOtherEntityMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("Years")); + } + + @Test + void testGetBenData_ageCalculation_months() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + // Create detail with DOB 6 months ago + RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); + LocalDate birthDate = LocalDate.now().minusMonths(6).minusDays(15); + detail.setDob(Timestamp.valueOf(birthDate.atStartOfDay())); + + when(beneficiaryRepo.getDetailsById(mapping.getBenDetailsId())).thenReturn(detail); + setupOtherEntityMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("Months") || result.contains("Month")); + } + + @Test + void testGetBenData_ageCalculation_days() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + // Create detail with DOB 15 days ago + RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); + LocalDate birthDate = LocalDate.now().minusDays(15); + detail.setDob(Timestamp.valueOf(birthDate.atStartOfDay())); + + when(beneficiaryRepo.getDetailsById(mapping.getBenDetailsId())).thenReturn(detail); + setupOtherEntityMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("Days") || result.contains("Day")); + } + + @Test + void testGetBenData_relatedBeneficiaryIds_parsing() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + // Create RMNCH details with related beneficiary IDs + RMNCHBeneficiaryDetailsRmnch rmnchDetails = createTestRMNCHBeneficiaryDetails(); + rmnchDetails.setRelatedBeneficiaryIdsDB("123,456,789"); + + when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); + + // Setup minimal required mocks (avoid unnecessary stubbings) + when(beneficiaryRepo.getDetailsById(mapping.getBenDetailsId())).thenReturn(createTestBeneficiaryDetail()); + when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); + when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(createTestBornBirthDetails()); + when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(createTestHouseHoldDetails()); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + verify(beneficiaryRepo).getDetailsByRegID(mapping.getBenRegId().longValue()); + } + + @Test + void testGetBenData_withHealthIdFetch_success() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + setupMappingDataMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("\"data\"")); + // Note: Health ID fetch happens in a try-catch block and doesn't affect the main flow + } + + @Test + void testGetBenData_healthIdFetchException_continuesProcessing() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + setupMappingDataMocks(); + setupHealthDetailsMocks(); + + // Mock ConfigProperties to throw exception + try (MockedStatic configMock = mockStatic(ConfigProperties.class)) { + configMock.when(() -> ConfigProperties.getPropertyByName(anyString())).thenThrow(new RuntimeException("Config error")); + + // Act + String result = service.getBenData(request, authorization); + + // Assert - Should still return valid result despite health ID fetch failure + assertNotNull(result); + assertTrue(result.contains("\"data\"")); + } + } + + @Test + void testGetBenData_getBenHealthDetails_withValidData() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + setupMappingDataMocks(); + + // Setup health details with valid data + Object[] healthIdData = {"test-health-id", "12345"}; + Object[] healthIdNumber = {healthIdData}; + when(beneficiaryRepo.getBenHealthIdNumber(mapping.getBenRegId())).thenReturn(healthIdNumber); + + List healthDetailsList = new ArrayList<>(); + Object[] healthDetails = {"health-id-123", "health-number-456", true}; + healthDetailsList.add(healthDetails); + when(beneficiaryRepo.getBenHealthDetails("test-health-id")).thenReturn(new ArrayList<>(healthDetailsList)); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("\"abhaHealthDetails\"")); + verify(beneficiaryRepo).getBenHealthIdNumber(mapping.getBenRegId()); + verify(beneficiaryRepo).getBenHealthDetails("test-health-id"); + } + + @Test + void testGetBenData_getBenHealthDetails_emptyHealthDetails() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + setupMappingDataMocks(); + + // Setup health details with valid health ID but no health details + Object[] healthIdData = {"test-health-id", "12345"}; + Object[] healthIdNumber = {healthIdData}; + when(beneficiaryRepo.getBenHealthIdNumber(mapping.getBenRegId())).thenReturn(healthIdNumber); + when(beneficiaryRepo.getBenHealthDetails("test-health-id")).thenReturn(new ArrayList<>()); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + verify(beneficiaryRepo).getBenHealthIdNumber(mapping.getBenRegId()); + verify(beneficiaryRepo).getBenHealthDetails("test-health-id"); + } + + @Test + void testGetBenData_getBenHealthDetails_nullHealthIdNumber() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + setupMappingDataMocks(); + + // Setup health details with null health ID number + Object[] healthIdData = {null, "12345"}; + Object[] healthIdNumber = {healthIdData}; + when(beneficiaryRepo.getBenHealthIdNumber(mapping.getBenRegId())).thenReturn(healthIdNumber); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + verify(beneficiaryRepo).getBenHealthIdNumber(mapping.getBenRegId()); + verify(beneficiaryRepo, never()).getBenHealthDetails(anyString()); + } + + @Test + void testGetBenData_nullBenRegId_skipsHealthDetails() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + RMNCHMBeneficiarymapping nullRegIdMapping = createTestMapping(); + nullRegIdMapping.setBenRegId(null); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(nullRegIdMapping); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + verify(beneficiaryRepo, never()).getBenHealthIdNumber(any()); + verify(beneficiaryRepo, never()).getDetailsByRegID(anyLong()); + verify(beneficiaryRepo, never()).getBornBirthByRegID(anyLong()); + } + + @Test + void testGetBenData_partialMappingData_handlesNulls() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + // Create mapping with only some fields set + RMNCHMBeneficiarymapping partialMapping = new RMNCHMBeneficiarymapping(); + partialMapping.setBenRegId(BigInteger.valueOf(100L)); + partialMapping.setBenDetailsId(BigInteger.valueOf(101L)); + // Leave other IDs null + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(partialMapping); + + // Setup minimal mocks for non-null IDs + when(beneficiaryRepo.getDetailsById(partialMapping.getBenDetailsId())).thenReturn(createTestBeneficiaryDetail()); + when(beneficiaryRepo.getBenIdFromRegID(partialMapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); + when(beneficiaryRepo.getDetailsByRegID(partialMapping.getBenRegId().longValue())).thenReturn(createTestRMNCHBeneficiaryDetails()); + when(beneficiaryRepo.getBornBirthByRegID(partialMapping.getBenRegId().longValue())).thenReturn(createTestBornBirthDetails()); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + verify(beneficiaryRepo).getDetailsById(partialMapping.getBenDetailsId()); + verify(beneficiaryRepo, never()).getAccountById(any()); + verify(beneficiaryRepo, never()).getImageById(anyLong()); + verify(beneficiaryRepo, never()).getAddressById(any()); + verify(beneficiaryRepo, never()).getContactById(any()); + } + + @Test + void testGetBenData_addressExceptionHandling_continuesProcessing() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + RMNCHMBeneficiaryaddress problematicAddress = createTestAddress(); + problematicAddress.setId(BigInteger.valueOf(999L)); + + List addressList = Arrays.asList(address, problematicAddress); + Page page = new PageImpl<>(addressList, pageRequest, 2); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(problematicAddress.getId())).thenThrow(new RuntimeException("Database error")); + + setupMappingDataMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + assertTrue(result.contains("\"data\"")); + // Should have 1 successful result despite one address failing + verify(beneficiaryRepo).getByAddressID(address.getId()); + verify(beneficiaryRepo).getByAddressID(problematicAddress.getId()); + } + + @Test + void testGetBenData_nullDob_skipsAgeCalculation() throws Exception { + // Arrange + PageRequest pageRequest = PageRequest.of(0, 10); + List addressList = Arrays.asList(address); + Page page = new PageImpl<>(addressList, pageRequest, 1); + + when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); + when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + + // Create detail with null DOB + RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); + detail.setDob(null); + + when(beneficiaryRepo.getDetailsById(mapping.getBenDetailsId())).thenReturn(detail); + setupOtherEntityMocks(); + setupHealthDetailsMocks(); + + // Act + String result = service.getBenData(request, authorization); + + // Assert + assertNotNull(result); + // Should still process successfully without age calculation + assertTrue(result.contains("\"beneficiaryDetails\"")); + } + + // Helper methods to create test data + private RMNCHMBeneficiaryaddress createTestAddress() { + RMNCHMBeneficiaryaddress addr = new RMNCHMBeneficiaryaddress(); + addr.setId(BigInteger.valueOf(1L)); + addr.setVanID(1); + addr.setCreatedBy("testUser"); + addr.setPermCountry("India"); + addr.setPermState("Test State"); + addr.setDistrictnamePerm("Test District"); + addr.setPermSubDistrict("Test Block"); + addr.setVillagenamePerm("Test Village"); + addr.setPermServicePoint("Test Service Point"); + addr.setPermZone("Test Zone"); + addr.setPermAddrLine1("Address Line 1"); + addr.setPermAddrLine2("Address Line 2"); + addr.setPermAddrLine3("Address Line 3"); + addr.setCountyid(1); + addr.setStatePerm(1); + addr.setDistrictidPerm(1); + addr.setPermSubDistrictId(1); + addr.setVillageidPerm(1); + addr.setPermServicePointId(1); + addr.setPermZoneID(1); + return addr; + } + + private RMNCHMBeneficiarymapping createTestMapping() { + RMNCHMBeneficiarymapping map = new RMNCHMBeneficiarymapping(); + map.setBenRegId(BigInteger.valueOf(100L)); + map.setBenDetailsId(BigInteger.valueOf(101L)); + map.setBenAccountID(BigInteger.valueOf(102L)); + map.setBenImageId(BigInteger.valueOf(103L)); + map.setBenAddressId(BigInteger.valueOf(104L)); + map.setBenContactsId(BigInteger.valueOf(105L)); + return map; + } + + private RMNCHMBeneficiarydetail createTestBeneficiaryDetail() { + RMNCHMBeneficiarydetail detail = new RMNCHMBeneficiarydetail(); + detail.setFirstName("John"); + detail.setLastName("Doe"); + detail.setFatherName("Father Name"); + detail.setMotherName("Mother Name"); + detail.setSpousename("Spouse Name"); + detail.setGender("Male"); + detail.setGenderId(1); + detail.setDob(currentTime); + detail.setMaritalstatus("Married"); + detail.setMaritalstatusId(2); + detail.setMarriageDate(currentTime); + detail.setReligion("Hindu"); + detail.setReligionID(BigInteger.valueOf(1L)); + detail.setCommunity("General"); + detail.setCommunityId(1); + detail.setLiteracyStatus("Literate"); + detail.setCreatedBy("testUser"); + return detail; + } + + private RMNCHMBeneficiaryAccount createTestBeneficiaryAccount() { + RMNCHMBeneficiaryAccount account = new RMNCHMBeneficiaryAccount(); + account.setNameOfBank("Test Bank"); + account.setBranchName("Test Branch"); + account.setIfscCode("TEST0001"); + account.setBankAccount("1234567890"); + return account; + } + + private RMNCHMBeneficiaryImage createTestBeneficiaryImage() { + RMNCHMBeneficiaryImage image = new RMNCHMBeneficiaryImage(); + image.setUser_image("base64encodedimage"); + return image; + } + + private RMNCHMBeneficiarycontact createTestBeneficiaryContact() { + RMNCHMBeneficiarycontact contact = new RMNCHMBeneficiarycontact(); + contact.setPreferredPhoneNum("9876543210"); + return contact; + } + + private RMNCHBeneficiaryDetailsRmnch createTestRMNCHBeneficiaryDetails() { + RMNCHBeneficiaryDetailsRmnch rmnchDetails = new RMNCHBeneficiaryDetailsRmnch(); + rmnchDetails.setHouseoldId(200L); + rmnchDetails.setCreatedBy("testUser"); + return rmnchDetails; + } + + private RMNCHHouseHoldDetails createTestHouseHoldDetails() { + RMNCHHouseHoldDetails houseHold = new RMNCHHouseHoldDetails(); + houseHold.setId(200L); + return houseHold; + } + + private RMNCHBornBirthDetails createTestBornBirthDetails() { + RMNCHBornBirthDetails birthDetails = new RMNCHBornBirthDetails(); + birthDetails.setBenRegId(100L); + return birthDetails; + } + + private void setupMappingDataMocks() { + RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); + RMNCHMBeneficiaryAccount account = createTestBeneficiaryAccount(); + RMNCHMBeneficiaryImage image = createTestBeneficiaryImage(); + RMNCHMBeneficiarycontact contact = createTestBeneficiaryContact(); + RMNCHBeneficiaryDetailsRmnch rmnchDetails = createTestRMNCHBeneficiaryDetails(); + RMNCHHouseHoldDetails houseHold = createTestHouseHoldDetails(); + RMNCHBornBirthDetails birthDetails = createTestBornBirthDetails(); + + when(beneficiaryRepo.getDetailsById(mapping.getBenDetailsId())).thenReturn(detail); + when(beneficiaryRepo.getAccountById(mapping.getBenAccountID())).thenReturn(account); + when(beneficiaryRepo.getImageById(mapping.getBenImageId().longValue())).thenReturn(image); + when(beneficiaryRepo.getAddressById(mapping.getBenAddressId())).thenReturn(address); + when(beneficiaryRepo.getContactById(mapping.getBenContactsId())).thenReturn(contact); + when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); + when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); + when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(birthDetails); + when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(houseHold); + when(beneficiaryRepo.getUserIDByUserName("testUser")).thenReturn(123); + } + + private void setupCompleteEntityMocks() { + setupMappingDataMocks(); + } + + private void setupOtherEntityMocks() { + RMNCHMBeneficiaryAccount account = createTestBeneficiaryAccount(); + RMNCHMBeneficiaryImage image = createTestBeneficiaryImage(); + RMNCHMBeneficiarycontact contact = createTestBeneficiaryContact(); + RMNCHBeneficiaryDetailsRmnch rmnchDetails = createTestRMNCHBeneficiaryDetails(); + RMNCHHouseHoldDetails houseHold = createTestHouseHoldDetails(); + RMNCHBornBirthDetails birthDetails = createTestBornBirthDetails(); + + when(beneficiaryRepo.getAccountById(mapping.getBenAccountID())).thenReturn(account); + when(beneficiaryRepo.getImageById(mapping.getBenImageId().longValue())).thenReturn(image); + when(beneficiaryRepo.getAddressById(mapping.getBenAddressId())).thenReturn(address); + when(beneficiaryRepo.getContactById(mapping.getBenContactsId())).thenReturn(contact); + when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); + when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); + when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(birthDetails); + when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(houseHold); + when(beneficiaryRepo.getUserIDByUserName("testUser")).thenReturn(123); + } + + private void setupHealthDetailsMocks() { + Object[] healthIdData = {"test-health-id", "12345"}; + Object[] healthIdNumber = {healthIdData}; + when(beneficiaryRepo.getBenHealthIdNumber(mapping.getBenRegId())).thenReturn(healthIdNumber); + when(beneficiaryRepo.getBenHealthDetails("test-health-id")).thenReturn(new ArrayList<>()); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/CbacServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/CbacServiceImplTest.java new file mode 100644 index 000000000..b8b972cba --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/CbacServiceImplTest.java @@ -0,0 +1,142 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.iemr.flw.domain.identity.CbacAdditionalDetails; +import com.iemr.flw.domain.identity.CbacDetails; +import com.iemr.flw.dto.identity.CbacDTO; +import com.iemr.flw.dto.identity.CbacStatus; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.identity.CbacAdditionalDetailRepo; +import com.iemr.flw.repo.identity.CbacRepo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; + +import java.lang.reflect.Field; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class CbacServiceImplTest { + @Mock + private CbacRepo cbacRepo; + @Mock + private CbacAdditionalDetailRepo cbacAddRepo; + @Mock + private BeneficiaryRepo beneficiaryRepo; + @Mock + private ObjectMapper mapper; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private CbacServiceImpl cbacService; + + @BeforeEach + void setUp() throws Exception { + Field field = CbacServiceImpl.class.getDeclaredField("cbac_page_size"); + field.setAccessible(true); + field.set(cbacService, "10"); + } + + @Test + void getByUserId_success() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + int pageNo = 0; + when(dto.getAshaId()).thenReturn(ashaId); + when(dto.getFromDate()).thenReturn(fromDate); + when(dto.getToDate()).thenReturn(toDate); + when(dto.getPageNo()).thenReturn(pageNo); + when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); + int pageSize = 10; + PageRequest pageRequest = PageRequest.of(pageNo, pageSize); + // Create CbacDetails with proper IDs + CbacDetails cbacDetails1 = new CbacDetails(); + cbacDetails1.setBeneficiaryRegId(100L); + cbacDetails1.setCbacDetailsId(1L); + CbacDetails cbacDetails2 = new CbacDetails(); + cbacDetails2.setBeneficiaryRegId(200L); + cbacDetails2.setCbacDetailsId(2L); + List cbacDetailsList = Arrays.asList(cbacDetails1, cbacDetails2); + Page cbacPage = new org.springframework.data.domain.PageImpl<>(cbacDetailsList, pageRequest, cbacDetailsList.size()); + when(cbacRepo.getAllByCreatedBy("user1", fromDate, toDate, pageRequest)).thenReturn(cbacPage); + when(beneficiaryRepo.getBenIdFromRegID(anyLong())).thenReturn(BigInteger.valueOf(1L)); + when(cbacAddRepo.findCbacAdditionalDetail(anyLong())).thenReturn(new CbacAdditionalDetails()); + when(mapper.convertValue(any(CbacDetails.class), eq(CbacDTO.class))).thenReturn(new CbacDTO()); + String json = cbacService.getByUserId(dto); + assertNotNull(json); + @SuppressWarnings("unchecked") + Map result = new Gson().fromJson(json, Map.class); + assertTrue(result.containsKey("data")); + assertTrue(result.containsKey("pageSize")); + assertTrue(result.containsKey("totalPage")); + } + + @Test + void getByUserId_exception() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + when(beneficiaryRepo.getUserName(anyInt())).thenThrow(new RuntimeException("fail")); + String json = cbacService.getByUserId(dto); + assertNull(json); + } + + @Test + void save_new_success() { + CbacDTO dto = new CbacDTO(); + dto.setBeneficiaryId(1L); + java.sql.Timestamp createdDate = java.sql.Timestamp.valueOf("2023-08-16 00:00:00"); + dto.setCreatedDate(createdDate); + List dtos = Collections.singletonList(dto); + when(beneficiaryRepo.getRegIDFromBenId(1L)).thenReturn(2L); + CbacDetails cbacDetails = new CbacDetails(); + cbacDetails.setCreatedDate(createdDate); + when(modelMapper.map(dto, CbacDetails.class)).thenReturn(cbacDetails); + when(cbacRepo.findCbacDetailsByBeneficiaryRegIdAndCreatedDate(2L, createdDate)).thenReturn(null); + CbacDetails savedCbac = new CbacDetails(); + savedCbac.setCbacDetailsId(5L); + when(cbacRepo.save(any(CbacDetails.class))).thenReturn(savedCbac); + CbacAdditionalDetails cbacAdditionalDetails = new CbacAdditionalDetails(); + when(modelMapper.map(dto, CbacAdditionalDetails.class)).thenReturn(cbacAdditionalDetails); + when(cbacAddRepo.saveAll(anyList())).thenReturn(Collections.emptyList()); + String json = cbacService.save(dtos); + assertNotNull(json); + CbacStatus[] arr = new Gson().fromJson(json, CbacStatus[].class); + assertEquals(1, arr.length); + assertEquals("Success", arr[0].getStatus()); + } + + @Test + void save_existing_fail() { + CbacDTO dto = new CbacDTO(); + dto.setBeneficiaryId(1L); + java.sql.Timestamp createdDate = java.sql.Timestamp.valueOf("2023-08-16 00:00:00"); + dto.setCreatedDate(createdDate); + List dtos = Collections.singletonList(dto); + when(beneficiaryRepo.getRegIDFromBenId(1L)).thenReturn(2L); + CbacDetails cbacDetails = new CbacDetails(); + cbacDetails.setCreatedDate(createdDate); + when(modelMapper.map(dto, CbacDetails.class)).thenReturn(cbacDetails); + CbacDetails existing = new CbacDetails(); + when(cbacRepo.findCbacDetailsByBeneficiaryRegIdAndCreatedDate(2L, createdDate)).thenReturn(existing); + String json = cbacService.save(dtos); + assertNotNull(json); + CbacStatus[] arr = new Gson().fromJson(json, CbacStatus[].class); + assertEquals(1, arr.length); + assertEquals("Fail", arr[0].getStatus()); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java new file mode 100644 index 000000000..5ae694abc --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java @@ -0,0 +1,745 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class ChildCareServiceImplTest { + + @Mock + private HbycRepo hbycRepo; + @Mock + private BeneficiaryRepo beneficiaryRepo; + @Mock + private HbncVisitRepo hbncVisitRepo; + @Mock + private HbncVisitCardRepo hbncVisitCardRepo; + @Mock + private HbncPart1Repo hbncPart1Repo; + @Mock + private HbncPart2repo hbncPart2repo; + @Mock + private IncentivesRepo incentivesRepo; + @Mock + private UserServiceRoleRepo userRepo; + @Mock + private IncentiveRecordRepo recordRepo; + @Mock + private ChildVaccinationRepo childVaccinationRepo; + @Mock + private VaccineRepo vaccineRepo; + + @InjectMocks + private ChildCareServiceImpl service; + + private Timestamp currentTime; + + @BeforeEach + void setUp() { + currentTime = Timestamp.from(Instant.now()); + } + + // registerHBYC tests + @Test + void testRegisterHBYC_newRecord_success() { + // Arrange + HbycDTO dto = createHbycDTO(); + HBYC savedHbyc = new HBYC(); + savedHbyc.setId(1L); + + when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) + .thenReturn(null); + when(hbycRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedHbyc)); + + // Act + String result = service.registerHBYC(Arrays.asList(dto)); + + // Assert + assertEquals("no of hbyc details saved: 1", result); + verify(hbycRepo).findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate()); + verify(hbycRepo).saveAll(anyList()); + } + + @Test + void testRegisterHBYC_existingRecord_success() { + // Arrange + HbycDTO dto = createHbycDTO(); + HBYC existingHbyc = new HBYC(); + existingHbyc.setId(5L); + + when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) + .thenReturn(existingHbyc); + when(hbycRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingHbyc)); + + // Act + String result = service.registerHBYC(Arrays.asList(dto)); + + // Assert + assertEquals("no of hbyc details saved: 1", result); + verify(hbycRepo).findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate()); + verify(hbycRepo).saveAll(anyList()); + } + + @Test + void testRegisterHBYC_exception() { + // Arrange + HbycDTO dto = createHbycDTO(); + when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = service.registerHBYC(Arrays.asList(dto)); + + // Assert + assertNull(result); + } + + // getHbycRecords tests + @Test + void testGetHbycRecords_success() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + String userName = "testUser"; + HBYC hbyc = new HBYC(); + hbyc.setId(1L); + hbyc.setBenId(123L); + + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); + when(hbycRepo.getAllHbycByBenId(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(hbyc)); + + // Act + List result = service.getHbycRecords(dto); + + // Assert + assertNotNull(result); + assertEquals(1, result.size()); + verify(beneficiaryRepo).getUserName(dto.getAshaId()); + verify(hbycRepo).getAllHbycByBenId(userName, dto.getFromDate(), dto.getToDate()); + } + + @Test + void testGetHbycRecords_exception() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); + + // Act + List result = service.getHbycRecords(dto); + + // Assert + assertNull(result); + } + + // getHBNCDetails tests + @Test + void testGetHBNCDetails_success() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + String userName = "testUser"; + + HbncVisit hbncVisit = new HbncVisit(); + hbncVisit.setId(1L); + hbncVisit.setBenId(123L); + hbncVisit.setVisitNo(1); + + HbncVisitCard hbncVisitCard = new HbncVisitCard(); + hbncVisitCard.setId(2L); + hbncVisitCard.setBenId(124L); + hbncVisitCard.setVisitNo(2); + + HbncPart1 hbncPart1 = new HbncPart1(); + hbncPart1.setId(3L); + hbncPart1.setBenId(125L); + hbncPart1.setVisitNo(1); + + HbncPart2 hbncPart2 = new HbncPart2(); + hbncPart2.setId(4L); + hbncPart2.setBenId(126L); + hbncPart2.setVisitNo(2); + + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); + when(hbncVisitRepo.getHbncVisitDetails(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(hbncVisit)); + when(hbncVisitCardRepo.getHbncVisitCardDetails(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(hbncVisitCard)); + when(hbncPart1Repo.getHbncPart1Details(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(hbncPart1)); + when(hbncPart2repo.getHbncPart2Details(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(hbncPart2)); + + // Act + List result = service.getHBNCDetails(dto); + + // Assert + assertNotNull(result); + assertEquals(4, result.size()); + verify(beneficiaryRepo).getUserName(dto.getAshaId()); + verify(hbncVisitRepo).getHbncVisitDetails(userName, dto.getFromDate(), dto.getToDate()); + verify(hbncVisitCardRepo).getHbncVisitCardDetails(userName, dto.getFromDate(), dto.getToDate()); + verify(hbncPart1Repo).getHbncPart1Details(userName, dto.getFromDate(), dto.getToDate()); + verify(hbncPart2repo).getHbncPart2Details(userName, dto.getFromDate(), dto.getToDate()); + } + + @Test + void testGetHBNCDetails_exception() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); + + // Act + List result = service.getHBNCDetails(dto); + + // Assert + assertNull(result); + } + + // saveHBNCDetails tests + @Test + void testSaveHBNCDetails_hbncVisitDTO_newRecord_success() { + // Arrange + HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); + when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) + .thenReturn(null); + when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncVisit())); + when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); + + // Act + String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); + + // Assert + assertEquals("no of hbnc details saved: 1", result); + verify(hbncVisitRepo).findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); + verify(hbncVisitRepo).saveAll(anyList()); + } + + @Test + void testSaveHBNCDetails_hbncVisitDTO_existingRecord_success() { + // Arrange + HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); + HbncVisit existingVisit = new HbncVisit(); + existingVisit.setId(5L); + + when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) + .thenReturn(existingVisit); + when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); + when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); + + // Act + String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); + + // Assert + assertEquals("no of hbnc details saved: 1", result); + verify(hbncVisitRepo).findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); + verify(hbncVisitRepo).saveAll(anyList()); + } + + @Test + void testSaveHBNCDetails_hbncVisitCardDTO_newRecord_success() { + // Arrange + HbncRequestDTO requestDTO = createHbncRequestDTOWithVisitCard(); + when(hbncVisitCardRepo.findHbncVisitCardByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) + .thenReturn(null); + when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncVisitCard())); + when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); + + // Act + String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); + + // Assert + assertEquals("no of hbnc details saved: 1", result); + verify(hbncVisitCardRepo).findHbncVisitCardByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); + verify(hbncVisitCardRepo).saveAll(anyList()); + } + + @Test + void testSaveHBNCDetails_hbncPart1DTO_newRecord_success() { + // Arrange + HbncRequestDTO requestDTO = createHbncRequestDTOWithPart1(); + when(hbncPart1Repo.findHbncPart1ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) + .thenReturn(null); + when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncPart1())); + when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); + + // Act + String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); + + // Assert + assertEquals("no of hbnc details saved: 1", result); + verify(hbncPart1Repo).findHbncPart1ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); + verify(hbncPart1Repo).saveAll(anyList()); + } + + @Test + void testSaveHBNCDetails_hbncPart2DTO_newRecord_success() { + // Arrange + HbncRequestDTO requestDTO = createHbncRequestDTOWithPart2(); + when(hbncPart2repo.findHbncPart2ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) + .thenReturn(null); + when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncPart2())); + + // Act + String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); + + // Assert + assertEquals("no of hbnc details saved: 1", result); + verify(hbncPart2repo).findHbncPart2ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); + verify(hbncPart2repo).saveAll(anyList()); + } + + @Test + void testSaveHBNCDetails_exception() { + // Arrange + HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); + when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); + + // Assert + assertNull(result); + } + + // getChildVaccinationDetails tests + @Test + void testGetChildVaccinationDetails_success() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + String userName = "testUser"; + ChildVaccination vaccination = new ChildVaccination(); + vaccination.setId(1L); + vaccination.setBeneficiaryRegId(100L); + vaccination.setVaccineName("BCG"); + + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); + when(childVaccinationRepo.getChildVaccinationDetails(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(vaccination)); + when(beneficiaryRepo.getBenIdFromRegID(vaccination.getBeneficiaryRegId())) + .thenReturn(BigInteger.valueOf(123L)); + + // Act + List result = service.getChildVaccinationDetails(dto); + + // Assert + assertNotNull(result); + assertEquals(1, result.size()); + assertEquals(123L, result.get(0).getBeneficiaryId()); + verify(beneficiaryRepo).getUserName(dto.getAshaId()); + verify(childVaccinationRepo).getChildVaccinationDetails(userName, dto.getFromDate(), dto.getToDate()); + verify(beneficiaryRepo).getBenIdFromRegID(vaccination.getBeneficiaryRegId()); + } + + @Test + void testGetChildVaccinationDetails_exception() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); + + // Act + List result = service.getChildVaccinationDetails(dto); + + // Assert + assertNull(result); + } + + // saveChildVaccinationDetails tests + @Test + void testSaveChildVaccinationDetails_newRecord_success() { + // Arrange + ChildVaccinationDTO dto = createChildVaccinationDTO(); + Long benRegId = 100L; + ChildVaccination savedVaccination = new ChildVaccination(); + savedVaccination.setId(1L); + savedVaccination.setBeneficiaryRegId(benRegId); + savedVaccination.setVaccineId(dto.getVaccineId()); + savedVaccination.setCreatedBy(dto.getCreatedBy()); + savedVaccination.setCreatedDate(dto.getCreatedDate()); + + when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); + when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( + benRegId, dto.getCreatedDate(), dto.getVaccineName())) + .thenReturn(null); + when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); + // Mocks for checkAndAddIncentives method + when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(dto.getBeneficiaryId())); + when(userRepo.getUserIdByName(dto.getCreatedBy())).thenReturn(1); + when(vaccineRepo.getImmunizationServiceIdByVaccineId(dto.getVaccineId().shortValue())).thenReturn(1); + // Additional mocks for incentive logic (immunizationServiceId < 6) + IncentiveActivity incentiveActivity = new IncentiveActivity(); + incentiveActivity.setId(1L); + incentiveActivity.setName("IMMUNIZATION_0_1"); + incentiveActivity.setRate(100); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")).thenReturn(incentiveActivity); + when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); + when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()))).thenReturn(null); + when(recordRepo.save(any(IncentiveActivityRecord.class))).thenReturn(new IncentiveActivityRecord()); + + // Act + String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); + + // Assert + assertEquals("No of child vaccination details saved: 1", result); + verify(beneficiaryRepo).getRegIDFromBenId(dto.getBeneficiaryId()); + verify(childVaccinationRepo).findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( + benRegId, dto.getCreatedDate(), dto.getVaccineName()); + verify(childVaccinationRepo).saveAll(anyList()); + } + + @Test + void testSaveChildVaccinationDetails_existingRecord_success() { + // Arrange + ChildVaccinationDTO dto = createChildVaccinationDTO(); + Long benRegId = 100L; + ChildVaccination existingVaccination = new ChildVaccination(); + existingVaccination.setId(5L); + existingVaccination.setBeneficiaryRegId(benRegId); + existingVaccination.setVaccineId(dto.getVaccineId()); + existingVaccination.setCreatedBy(dto.getCreatedBy()); + existingVaccination.setCreatedDate(dto.getCreatedDate()); + + when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); + when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( + benRegId, dto.getCreatedDate(), dto.getVaccineName())) + .thenReturn(existingVaccination); + when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVaccination)); + // Mocks for checkAndAddIncentives method + when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(dto.getBeneficiaryId())); + when(userRepo.getUserIdByName(dto.getCreatedBy())).thenReturn(1); + when(vaccineRepo.getImmunizationServiceIdByVaccineId(dto.getVaccineId().shortValue())).thenReturn(1); + // Additional mocks for incentive logic (immunizationServiceId < 6) + IncentiveActivity incentiveActivity = new IncentiveActivity(); + incentiveActivity.setId(1L); + incentiveActivity.setName("IMMUNIZATION_0_1"); + incentiveActivity.setRate(100); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")).thenReturn(incentiveActivity); + when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); + when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()))).thenReturn(null); + when(recordRepo.save(any(IncentiveActivityRecord.class))).thenReturn(new IncentiveActivityRecord()); + + // Act + String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); + + // Assert + assertEquals("No of child vaccination details saved: 1", result); + verify(beneficiaryRepo).getRegIDFromBenId(dto.getBeneficiaryId()); + verify(childVaccinationRepo).findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( + benRegId, dto.getCreatedDate(), dto.getVaccineName()); + verify(childVaccinationRepo).saveAll(anyList()); + } + + @Test + void testSaveChildVaccinationDetails_withIncentives_firstYear_success() { + // Arrange + ChildVaccinationDTO dto = createChildVaccinationDTO(); + dto.setVaccineId(1); // First year vaccine + Long benRegId = 100L; + ChildVaccination savedVaccination = new ChildVaccination(); + savedVaccination.setId(1L); + savedVaccination.setBeneficiaryRegId(benRegId); + savedVaccination.setVaccineId(1); + savedVaccination.setCreatedDate(currentTime); + savedVaccination.setCreatedBy("testUser"); + + IncentiveActivity incentiveActivity = new IncentiveActivity(); + incentiveActivity.setId(1L); + incentiveActivity.setRate(100); + + when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); + when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( + benRegId, dto.getCreatedDate(), dto.getVaccineName())) + .thenReturn(null); + when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); + when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); + when(userRepo.getUserIdByName("testUser")).thenReturn(1); + when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 1)).thenReturn(1); // First year vaccine + when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")) + .thenReturn(incentiveActivity); + when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); + when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, 123L)) + .thenReturn(null); + + // Act + String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); + + // Assert + assertEquals("No of child vaccination details saved: 1", result); + verify(recordRepo).save(any(IncentiveActivityRecord.class)); + } + + @Test + void testSaveChildVaccinationDetails_withIncentives_secondYear_success() { + // Arrange + ChildVaccinationDTO dto = createChildVaccinationDTO(); + dto.setVaccineId(7); // Second year vaccine + Long benRegId = 100L; + ChildVaccination savedVaccination = new ChildVaccination(); + savedVaccination.setId(1L); + savedVaccination.setBeneficiaryRegId(benRegId); + savedVaccination.setVaccineId(7); + savedVaccination.setCreatedDate(currentTime); + savedVaccination.setCreatedBy("testUser"); + + IncentiveActivity incentiveActivity = new IncentiveActivity(); + incentiveActivity.setId(2L); + incentiveActivity.setRate(150); + + when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); + when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( + benRegId, dto.getCreatedDate(), dto.getVaccineName())) + .thenReturn(null); + when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); + when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); + when(userRepo.getUserIdByName("testUser")).thenReturn(1); + when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 7)).thenReturn(7); // Second year vaccine + when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_1_2", "IMMUNIZATION")) + .thenReturn(incentiveActivity); + when(childVaccinationRepo.getSecondYearVaccineCountForBenId(benRegId)).thenReturn(3); + when(childVaccinationRepo.getSecondYearVaccineCount()).thenReturn(3); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, 123L)) + .thenReturn(null); + + // Act + String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); + + // Assert + assertEquals("No of child vaccination details saved: 1", result); + verify(recordRepo).save(any(IncentiveActivityRecord.class)); + } + + @Test + void testSaveChildVaccinationDetails_withIncentives_fifthYear_success() { + // Arrange + ChildVaccinationDTO dto = createChildVaccinationDTO(); + dto.setVaccineId(8); // Fifth year vaccine + Long benRegId = 100L; + ChildVaccination savedVaccination = new ChildVaccination(); + savedVaccination.setId(1L); + savedVaccination.setBeneficiaryRegId(benRegId); + savedVaccination.setVaccineId(8); + savedVaccination.setCreatedDate(currentTime); + savedVaccination.setCreatedBy("testUser"); + + IncentiveActivity incentiveActivity = new IncentiveActivity(); + incentiveActivity.setId(3L); + incentiveActivity.setRate(200); + + when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); + when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( + benRegId, dto.getCreatedDate(), dto.getVaccineName())) + .thenReturn(null); + when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); + when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); + when(userRepo.getUserIdByName("testUser")).thenReturn(1); + when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 8)).thenReturn(8); // Fifth year vaccine + when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_5", "IMMUNIZATION")) + .thenReturn(incentiveActivity); + when(childVaccinationRepo.checkDptVaccinatedUser(benRegId)).thenReturn(1); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(3L, currentTime, 123L)) + .thenReturn(null); + + // Act + String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); + + // Assert + assertEquals("No of child vaccination details saved: 1", result); + verify(recordRepo).save(any(IncentiveActivityRecord.class)); + } + + @Test + void testSaveChildVaccinationDetails_exception() { + // Arrange + ChildVaccinationDTO dto = createChildVaccinationDTO(); + when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); + + // Assert + assertNull(result); + } + + // getAllChildVaccines tests + @Test + void testGetAllChildVaccines_success() { + // Arrange + String category = "CHILD"; + Vaccine vaccine1 = createVaccine("Birth Dose Vaccines"); + Vaccine vaccine2 = createVaccine("6 Weeks Vaccines"); + Vaccine vaccine3 = createVaccine("10 Weeks Vaccines"); + Vaccine vaccine4 = createVaccine("14 Weeks Vaccines"); + Vaccine vaccine5 = createVaccine("9-12 Months"); + Vaccine vaccine6 = createVaccine("16-24 Months Vaccines"); + Vaccine vaccine7 = createVaccine("5-6 Years Vaccine"); + Vaccine vaccine8 = createVaccine("10 Years Vaccine"); + Vaccine vaccine9 = createVaccine("16 Years Vaccine"); + Vaccine vaccine10 = createVaccine("Unknown Category"); + + when(vaccineRepo.getAllByCategory(category)).thenReturn(Arrays.asList( + vaccine1, vaccine2, vaccine3, vaccine4, vaccine5, + vaccine6, vaccine7, vaccine8, vaccine9, vaccine10 + )); + + // Act + List result = service.getAllChildVaccines(category); + + // Assert + assertNotNull(result); + assertEquals(10, result.size()); + + // Verify immunization service mappings + assertEquals("BIRTH", result.get(0).getImmunizationService()); + assertEquals("WEEK_6", result.get(1).getImmunizationService()); + assertEquals("WEEK_10", result.get(2).getImmunizationService()); + assertEquals("WEEK_14", result.get(3).getImmunizationService()); + assertEquals("MONTH_9_12", result.get(4).getImmunizationService()); + assertEquals("MONTH_16_24", result.get(5).getImmunizationService()); + assertEquals("YEAR_5_6", result.get(6).getImmunizationService()); + assertEquals("YEAR_10", result.get(7).getImmunizationService()); + assertEquals("YEAR_16", result.get(8).getImmunizationService()); + assertEquals("CATCH_UP", result.get(9).getImmunizationService()); + + verify(vaccineRepo).getAllByCategory(category); + } + + @Test + void testGetAllChildVaccines_exception() { + // Arrange + String category = "CHILD"; + when(vaccineRepo.getAllByCategory(category)).thenThrow(new RuntimeException("Database error")); + + // Act + List result = service.getAllChildVaccines(category); + + // Assert + assertNull(result); + } + + // Helper methods to create test data + private HbycDTO createHbycDTO() { + HbycDTO dto = new HbycDTO(); + dto.setBenId(123L); + dto.setCreatedDate(currentTime); + dto.setCreatedBy("testUser"); + dto.setUpdatedDate(currentTime); + dto.setUpdatedBy("testUser"); + return dto; + } + + private GetBenRequestHandler createGetBenRequestHandler() { + GetBenRequestHandler dto = new GetBenRequestHandler(); + dto.setAshaId(1); + dto.setFromDate(currentTime); + dto.setToDate(currentTime); + return dto; + } + + private HbncRequestDTO createHbncRequestDTOWithVisit() { + HbncRequestDTO dto = new HbncRequestDTO(); + dto.setId(1L); + dto.setBenId(123L); + dto.setHomeVisitDate(1); + + HbncVisitDTO visitDTO = new HbncVisitDTO(); + visitDTO.setBenId(123L); + visitDTO.setVisitNo(1); + dto.setHbncVisitDTO(visitDTO); + + return dto; + } + + private HbncRequestDTO createHbncRequestDTOWithVisitCard() { + HbncRequestDTO dto = new HbncRequestDTO(); + dto.setId(2L); + dto.setBenId(124L); + dto.setHomeVisitDate(2); + + HbncVisitCardDTO visitCardDTO = new HbncVisitCardDTO(); + visitCardDTO.setBenId(124L); + visitCardDTO.setVisitNo(2); + dto.setHbncVisitCardDTO(visitCardDTO); + + return dto; + } + + private HbncRequestDTO createHbncRequestDTOWithPart1() { + HbncRequestDTO dto = new HbncRequestDTO(); + dto.setId(3L); + dto.setBenId(125L); + dto.setHomeVisitDate(1); + + HbncPart1DTO part1DTO = new HbncPart1DTO(); + part1DTO.setBenId(125L); + part1DTO.setVisitNo(1); + dto.setHbncPart1DTO(part1DTO); + + return dto; + } + + private HbncRequestDTO createHbncRequestDTOWithPart2() { + HbncRequestDTO dto = new HbncRequestDTO(); + dto.setId(4L); + dto.setBenId(126L); + dto.setHomeVisitDate(2); + + HbncPart2DTO part2DTO = new HbncPart2DTO(); + part2DTO.setBenId(126L); + part2DTO.setVisitNo(2); + dto.setHbncPart2DTO(part2DTO); + + return dto; + } + + private ChildVaccinationDTO createChildVaccinationDTO() { + ChildVaccinationDTO dto = new ChildVaccinationDTO(); + dto.setBeneficiaryId(123L); + dto.setVaccineName("BCG"); + dto.setVaccineId(1); + dto.setCreatedDate(currentTime); + dto.setCreatedBy("testUser"); + dto.setLastModDate(currentTime); + dto.setModifiedBy("testUser"); + return dto; + } + + private Vaccine createVaccine(String immunizationService) { + Vaccine vaccine = new Vaccine(); + vaccine.setVaccineId((short) 1); + vaccine.setVaccineName("Test Vaccine"); + vaccine.setImmunizationService(immunizationService); + return vaccine; + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/ChildServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/ChildServiceImplTest.java new file mode 100644 index 000000000..dba027636 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/ChildServiceImplTest.java @@ -0,0 +1,110 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.ChildRegister; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.ChildRegisterDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.ChildRegisterRepo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class ChildServiceImplTest { + @Mock + private ChildRegisterRepo childRepo; + @Mock + private BeneficiaryRepo beneficiaryRepo; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private ChildServiceImpl childService; + + @BeforeEach + void setUp() { + childService.modelMapper = modelMapper; + } + + @Test + void getByUserId_success() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + java.sql.Timestamp fromDate = java.sql.Timestamp.valueOf("2023-01-01 00:00:00"); + java.sql.Timestamp toDate = java.sql.Timestamp.valueOf("2023-12-31 00:00:00"); + when(dto.getAshaId()).thenReturn(ashaId); + when(dto.getFromDate()).thenReturn(fromDate); + when(dto.getToDate()).thenReturn(toDate); + when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); + List childList = Arrays.asList(new ChildRegister(), new ChildRegister()); + when(childRepo.getChildDetailsForUser(eq("user1"), eq(fromDate), eq(toDate))).thenReturn(childList); + when(modelMapper.map(any(ChildRegister.class), eq(ChildRegisterDTO.class))).thenReturn(new ChildRegisterDTO()); + String json = childService.getByUserId(dto); + assertNotNull(json); + ChildRegisterDTO[] arr = new Gson().fromJson(json, ChildRegisterDTO[].class); + assertEquals(2, arr.length); + } + + @Test + void getByUserId_exception() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + when(dto.getAshaId()).thenReturn(ashaId); + when(beneficiaryRepo.getUserName(anyInt())).thenThrow(new RuntimeException("fail")); + String json = childService.getByUserId(dto); + assertNull(json); + } + + @Test + void save_newChild_success() throws Exception { + ChildRegisterDTO dto = new ChildRegisterDTO(); + dto.setBenId(1L); + java.sql.Timestamp createdDate = java.sql.Timestamp.valueOf("2023-01-01 00:00:00"); + dto.setCreatedDate(createdDate); + when(childRepo.findChildRegisterByBenIdAndCreatedDate(anyLong(), any(java.sql.Timestamp.class))).thenReturn(null); + doAnswer(invocation -> { + List list = invocation.getArgument(0); + assertEquals(1, list.size()); + return null; + }).when(childRepo).saveAll(anyList()); + // modelMapper.map returns void for (ChildRegisterDTO, ChildRegister) + // No need to stub modelMapper.map for void methods; Mockito does nothing by default + String result = childService.save(Collections.singletonList(dto)); + assertTrue(result.contains("no of child details saved: 1")); + } + + @Test + void save_existingChild_success() throws Exception { + ChildRegisterDTO dto = new ChildRegisterDTO(); + dto.setBenId(2L); + java.sql.Timestamp createdDate = java.sql.Timestamp.valueOf("2023-01-02 00:00:00"); + dto.setCreatedDate(createdDate); + ChildRegister existing = new ChildRegister(); + existing.setId(99L); + when(childRepo.findChildRegisterByBenIdAndCreatedDate(anyLong(), any(java.sql.Timestamp.class))).thenReturn(existing); + doNothing().when(modelMapper).map(any(ChildRegisterDTO.class), any(ChildRegister.class)); + String result = childService.save(Collections.singletonList(dto)); + assertTrue(result.contains("no of child details saved: 1")); + } + + @Test + void save_exception() throws Exception { + ChildRegisterDTO dto = new ChildRegisterDTO(); + dto.setBenId(3L); + java.sql.Timestamp createdDate = java.sql.Timestamp.valueOf("2023-01-03 00:00:00"); + dto.setCreatedDate(createdDate); + when(childRepo.findChildRegisterByBenIdAndCreatedDate(anyLong(), any(java.sql.Timestamp.class))).thenThrow(new RuntimeException("fail")); + assertThrows(Exception.class, () -> childService.save(Collections.singletonList(dto))); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java new file mode 100644 index 000000000..b02330e46 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java @@ -0,0 +1,685 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.EligibleCoupleDTO; +import com.iemr.flw.dto.iemr.EligibleCoupleTrackingDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.lang.reflect.Field; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class CoupleServiceImplTest { + @Mock + private EligibleCoupleRegisterRepo eligibleCoupleRegisterRepo; + @Mock + private EligibleCoupleTrackingRepo eligibleCoupleTrackingRepo; + @Mock + private IncentivesRepo incentivesRepo; + @Mock + private UserServiceRoleRepo userRepo; + @Mock + private IncentiveRecordRepo recordRepo; + @Mock + private BeneficiaryRepo beneficiaryRepo; + @Mock + private ObjectMapper mapper; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private CoupleServiceImpl coupleService; + + @BeforeEach + void setUp() throws Exception { + // Set up ObjectMapper and ModelMapper fields using reflection + Field mapperField = CoupleServiceImpl.class.getDeclaredField("mapper"); + mapperField.setAccessible(true); + mapperField.set(coupleService, mapper); + + Field modelMapperField = CoupleServiceImpl.class.getDeclaredField("modelMapper"); + modelMapperField.setAccessible(true); + modelMapperField.set(coupleService, modelMapper); + } + + @Test + void registerEligibleCouple_existingECRWithIncentives_success() { + // Arrange + EligibleCoupleDTO dto = new EligibleCoupleDTO(); + dto.setBenId(1L); + dto.setNumLiveChildren(1); + dto.setMarriageFirstChildGap(3); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); + existingECR.setId(1L); + existingECR.setNumLiveChildren(0); + + IncentiveActivity activity = new IncentiveActivity(); + activity.setId(1L); + activity.getName(); + activity.setRate(100); + + when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) + .thenReturn(activity); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + .thenReturn(null); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + + // Act + String result = coupleService.registerEligibleCouple(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ecr details saved: 1", result); + verify(eligibleCoupleRegisterRepo).findEligibleCoupleRegisterByBenId(1L); + verify(incentivesRepo).findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING"); + verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + verify(userRepo).getUserIdByName("testUser"); + verify(eligibleCoupleRegisterRepo).saveAll(anyList()); + verify(recordRepo).saveAll(anyList()); + verify(modelMapper).map(dto, existingECR); + } + + @Test + void registerEligibleCouple_secondChildGapIncentive_success() { + // Arrange + EligibleCoupleDTO dto = new EligibleCoupleDTO(); + dto.setBenId(1L); + dto.setNumLiveChildren(2); + dto.setMarriageFirstChildGap(2); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); + existingECR.setId(1L); + existingECR.setNumLiveChildren(1); + + IncentiveActivity activity = new IncentiveActivity(); + activity.setId(2L); + activity.setName("Second child gap"); + activity.setRate(200); + + when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", "FAMILY PLANNING")) + .thenReturn(activity); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + .thenReturn(null); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + + // Act + String result = coupleService.registerEligibleCouple(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ecr details saved: 1", result); + verify(incentivesRepo).findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", "FAMILY PLANNING"); + } + + @Test + void registerEligibleCouple_newECR_success() { + // Arrange + EligibleCoupleDTO dto = new EligibleCoupleDTO(); + dto.setBenId(1L); + dto.setNumLiveChildren(0); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + EligibleCoupleRegister newECR = new EligibleCoupleRegister(); + newECR.setId(null); + + when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(null); + when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(newECR)); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + doAnswer(invocation -> { + EligibleCoupleDTO source = invocation.getArgument(0); + EligibleCoupleRegister target = invocation.getArgument(1); + target.setCreatedBy(source.getCreatedBy()); + return null; + }).when(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); + + // Act + String result = coupleService.registerEligibleCouple(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ecr details saved: 1", result); + verify(eligibleCoupleRegisterRepo).findEligibleCoupleRegisterByBenId(1L); + verify(eligibleCoupleRegisterRepo).saveAll(anyList()); + verify(recordRepo).saveAll(anyList()); + verify(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); + } + + @Test + void registerEligibleCouple_existingRecord_noIncentive() { + // Arrange + EligibleCoupleDTO dto = new EligibleCoupleDTO(); + dto.setBenId(1L); + dto.setNumLiveChildren(1); + dto.setMarriageFirstChildGap(3); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); + existingECR.setId(1L); + existingECR.setNumLiveChildren(0); + + IncentiveActivity activity = new IncentiveActivity(); + activity.setId(1L); + activity.setName("Marriage gap"); + activity.setRate(100); + + IncentiveActivityRecord existingRecord = new IncentiveActivityRecord(); + + when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) + .thenReturn(activity); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + .thenReturn(existingRecord); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + + // Act + String result = coupleService.registerEligibleCouple(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ecr details saved: 1", result); + verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + // getUserIdByName should still be called even for existing record due to service logic + verify(userRepo).getUserIdByName("testUser"); + } + + @Test + void registerEligibleCouple_exception_returnsError() { + // Arrange + EligibleCoupleDTO dto = new EligibleCoupleDTO(); + dto.setBenId(1L); + List dtoList = Arrays.asList(dto); + + when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = coupleService.registerEligibleCouple(dtoList); + + // Assert + assertNotNull(result); + assertTrue(result.startsWith("error while saving ecr details: ")); + assertTrue(result.contains("Database error")); + } + + @Test + void registerEligibleCoupleTracking_newECTWithAntaraIncentive_success() { + // Arrange + EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); + dto.setBenId(1L); + dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setMethodOfContraception("ANTRA Injection"); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + EligibleCoupleTracking newECT = new EligibleCoupleTracking(); + + IncentiveActivity antaraActivity = new IncentiveActivity(); + antaraActivity.setId(1L); + antaraActivity.setName("ANTARA_PROG_1"); + antaraActivity.setRate(500); + + when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) + .thenReturn(null); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING")) + .thenReturn(antaraActivity); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + .thenReturn(null); + when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(Arrays.asList(newECT)); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + doAnswer(invocation -> { + EligibleCoupleTrackingDTO source = invocation.getArgument(0); + EligibleCoupleTracking target = invocation.getArgument(1); + target.setCreatedBy(source.getCreatedBy()); + target.setMethodOfContraception(source.getMethodOfContraception()); + target.setBenId(source.getBenId()); + target.setCreatedDate(source.getCreatedDate()); + return null; + }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); + + // Act + String result = coupleService.registerEligibleCoupleTracking(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ect details saved: 1", result); + verify(eligibleCoupleTrackingRepo).findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate()); + verify(userRepo).getUserIdByName("testUser"); + verify(eligibleCoupleTrackingRepo).findCouplesHadAntara(1L); + verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING"); + verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + verify(eligibleCoupleTrackingRepo).saveAll(anyList()); + verify(recordRepo).saveAll(anyList()); + } + + @Test + void registerEligibleCoupleTracking_existingECTWithAntaraProg2_success() { + // Arrange + EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); + dto.setBenId(1L); + dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setMethodOfContraception("ANTRA Injection"); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + EligibleCoupleTracking existingECT = new EligibleCoupleTracking(); + existingECT.setId(1L); + + List antaraHistory = Arrays.asList(new EligibleCoupleTracking()); + + IncentiveActivity antaraActivity2 = new IncentiveActivity(); + antaraActivity2.setId(2L); + antaraActivity2.setName("ANTARA_PROG_2"); + antaraActivity2.setRate(600); + + when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) + .thenReturn(existingECT); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(antaraHistory); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_2", "FAMILY PLANNING")) + .thenReturn(antaraActivity2); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + .thenReturn(null); + when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECT)); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + doAnswer(invocation -> { + EligibleCoupleTrackingDTO source = invocation.getArgument(0); + EligibleCoupleTracking target = invocation.getArgument(1); + target.setCreatedBy(source.getCreatedBy()); + target.setMethodOfContraception(source.getMethodOfContraception()); + target.setBenId(source.getBenId()); + target.setCreatedDate(source.getCreatedDate()); + return null; + }).when(modelMapper).map(dto, existingECT); + + // Act + String result = coupleService.registerEligibleCoupleTracking(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ect details saved: 1", result); + verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_2", "FAMILY PLANNING"); + verify(modelMapper).map(dto, existingECT); + } + + @Test + void registerEligibleCoupleTracking_antaraProg3And4_success() { + // Test for ANTARA_PROG_3 (numAntaraDosage = 2) + EligibleCoupleTrackingDTO dto1 = new EligibleCoupleTrackingDTO(); + dto1.setBenId(1L); + dto1.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); + dto1.setMethodOfContraception("ANTRA Injection"); + dto1.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto1.setCreatedBy("testUser"); + + List antaraHistory3 = Arrays.asList( + new EligibleCoupleTracking(), new EligibleCoupleTracking() + ); + + IncentiveActivity antaraActivity3 = new IncentiveActivity(); + antaraActivity3.setId(3L); + antaraActivity3.setName("ANTARA_PROG_3"); + antaraActivity3.setRate(700); + + when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto1.getVisitDate())) + .thenReturn(null); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(antaraHistory3); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_3", "FAMILY PLANNING")) + .thenReturn(antaraActivity3); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + .thenReturn(null); + when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + doAnswer(invocation -> { + EligibleCoupleTrackingDTO source = invocation.getArgument(0); + EligibleCoupleTracking target = invocation.getArgument(1); + target.setCreatedBy(source.getCreatedBy()); + target.setMethodOfContraception(source.getMethodOfContraception()); + target.setBenId(source.getBenId()); + target.setCreatedDate(source.getCreatedDate()); + return null; + }).when(modelMapper).map(eq(dto1), any(EligibleCoupleTracking.class)); + + String result1 = coupleService.registerEligibleCoupleTracking(Arrays.asList(dto1)); + assertNotNull(result1); + verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_3", "FAMILY PLANNING"); + + // Test for ANTARA_PROG_4 (numAntaraDosage = 3) + reset(eligibleCoupleTrackingRepo); + reset(incentivesRepo); + reset(recordRepo); + reset(userRepo); + + EligibleCoupleTrackingDTO dto2 = new EligibleCoupleTrackingDTO(); + dto2.setBenId(2L); + dto2.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); + dto2.setMethodOfContraception("ANTRA Injection"); + dto2.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto2.setCreatedBy("testUser"); + + List antaraHistory4 = Arrays.asList( + new EligibleCoupleTracking(), new EligibleCoupleTracking(), new EligibleCoupleTracking() + ); + + IncentiveActivity antaraActivity4 = new IncentiveActivity(); + antaraActivity4.setId(4L); + antaraActivity4.setName("ANTARA_PROG_4"); + antaraActivity4.setRate(800); + + when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(2L, dto2.getVisitDate())) + .thenReturn(null); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleTrackingRepo.findCouplesHadAntara(2L)).thenReturn(antaraHistory4); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_4", "FAMILY PLANNING")) + .thenReturn(antaraActivity4); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + .thenReturn(null); + when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + doAnswer(invocation -> { + EligibleCoupleTrackingDTO source = invocation.getArgument(0); + EligibleCoupleTracking target = invocation.getArgument(1); + target.setCreatedBy(source.getCreatedBy()); + target.setMethodOfContraception(source.getMethodOfContraception()); + target.setBenId(source.getBenId()); + target.setCreatedDate(source.getCreatedDate()); + return null; + }).when(modelMapper).map(eq(dto2), any(EligibleCoupleTracking.class)); + + String result2 = coupleService.registerEligibleCoupleTracking(Arrays.asList(dto2)); + assertNotNull(result2); + verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_4", "FAMILY PLANNING"); + } + + @Test + void registerEligibleCoupleTracking_noIncentiveForNonAntara_success() { + // Arrange + EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); + dto.setBenId(1L); + dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setMethodOfContraception("Other method"); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) + .thenReturn(null); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); + when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + doAnswer(invocation -> { + EligibleCoupleTrackingDTO source = invocation.getArgument(0); + EligibleCoupleTracking target = invocation.getArgument(1); + target.setCreatedBy(source.getCreatedBy()); + target.setMethodOfContraception(source.getMethodOfContraception()); + target.setBenId(source.getBenId()); + target.setCreatedDate(source.getCreatedDate()); + return null; + }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); + + // Act + String result = coupleService.registerEligibleCoupleTracking(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ect details saved: 1", result); + verify(incentivesRepo, never()).findIncentiveMasterByNameAndGroup(anyString(), anyString()); + } + + @Test + void registerEligibleCoupleTracking_exception_returnsError() { + // Arrange + EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); + dto.setBenId(1L); + List dtoList = Arrays.asList(dto); + + when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(anyLong(), any())) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = coupleService.registerEligibleCoupleTracking(dtoList); + + // Assert + assertNotNull(result); + assertTrue(result.startsWith("error while saving ect details: ")); + assertTrue(result.contains("Database error")); + } + + @Test + void getEligibleCoupleRegRecords_success() { + // Arrange + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf(LocalDateTime.now().minusDays(30)); + Timestamp toDate = Timestamp.valueOf(LocalDateTime.now()); + + when(dto.getAshaId()).thenReturn(ashaId); + when(dto.getFromDate()).thenReturn(fromDate); + when(dto.getToDate()).thenReturn(toDate); + + String userName = "testUser"; + List registerList = Arrays.asList(new EligibleCoupleRegister()); + EligibleCoupleDTO mappedDTO = new EligibleCoupleDTO(); + + when(beneficiaryRepo.getUserName(ashaId)).thenReturn(userName); + when(eligibleCoupleRegisterRepo.getECRegRecords(userName, fromDate, toDate)).thenReturn(registerList); + when(mapper.convertValue(any(EligibleCoupleRegister.class), eq(EligibleCoupleDTO.class))) + .thenReturn(mappedDTO); + + // Act + String result = coupleService.getEligibleCoupleRegRecords(dto); + + // Assert + assertNotNull(result); + @SuppressWarnings("unchecked") + List resultList = new Gson().fromJson(result, List.class); + assertEquals(1, resultList.size()); + + verify(beneficiaryRepo).getUserName(ashaId); + verify(eligibleCoupleRegisterRepo).getECRegRecords(userName, fromDate, toDate); + verify(mapper).convertValue(any(EligibleCoupleRegister.class), eq(EligibleCoupleDTO.class)); + } + + @Test + void getEligibleCoupleRegRecords_exception_returnsNull() { + // Arrange + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + when(dto.getAshaId()).thenReturn(123); + when(beneficiaryRepo.getUserName(123)).thenThrow(new RuntimeException("Database error")); + + // Act + String result = coupleService.getEligibleCoupleRegRecords(dto); + + // Assert + assertNull(result); + verify(beneficiaryRepo).getUserName(123); + } + + @Test + void getEligibleCoupleTracking_success() { + // Arrange + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf(LocalDateTime.now().minusDays(30)); + Timestamp toDate = Timestamp.valueOf(LocalDateTime.now()); + + when(dto.getAshaId()).thenReturn(ashaId); + when(dto.getFromDate()).thenReturn(fromDate); + when(dto.getToDate()).thenReturn(toDate); + + String userName = "testUser"; + List trackingList = Arrays.asList(new EligibleCoupleTracking()); + EligibleCoupleTrackingDTO mappedDTO = new EligibleCoupleTrackingDTO(); + + when(beneficiaryRepo.getUserName(ashaId)).thenReturn(userName); + when(eligibleCoupleTrackingRepo.getECTrackRecords(userName, fromDate, toDate)).thenReturn(trackingList); + when(mapper.convertValue(any(EligibleCoupleTracking.class), eq(EligibleCoupleTrackingDTO.class))) + .thenReturn(mappedDTO); + + // Act + List result = coupleService.getEligibleCoupleTracking(dto); + + // Assert + assertNotNull(result); + assertEquals(1, result.size()); + assertEquals(mappedDTO, result.get(0)); + + verify(beneficiaryRepo).getUserName(ashaId); + verify(eligibleCoupleTrackingRepo).getECTrackRecords(userName, fromDate, toDate); + verify(mapper).convertValue(any(EligibleCoupleTracking.class), eq(EligibleCoupleTrackingDTO.class)); + } + + @Test + void getEligibleCoupleTracking_exception_returnsNull() { + // Arrange + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + when(dto.getAshaId()).thenReturn(123); + when(beneficiaryRepo.getUserName(123)).thenThrow(new RuntimeException("Database error")); + + // Act + List result = coupleService.getEligibleCoupleTracking(dto); + + // Assert + assertNull(result); + verify(beneficiaryRepo).getUserName(123); + } + + @Test + void registerEligibleCoupleTracking_nullIncentiveActivity_noRecordAdded() { + // Arrange + EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); + dto.setBenId(1L); + dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setMethodOfContraception("ANTRA Injection"); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) + .thenReturn(null); + when(userRepo.getUserIdByName("testUser")).thenReturn(123); + when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING")) + .thenReturn(null); + when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + doAnswer(invocation -> { + EligibleCoupleTrackingDTO source = invocation.getArgument(0); + EligibleCoupleTracking target = invocation.getArgument(1); + target.setCreatedBy(source.getCreatedBy()); + target.setMethodOfContraception(source.getMethodOfContraception()); + target.setBenId(source.getBenId()); + target.setCreatedDate(source.getCreatedDate()); + return null; + }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); + + // Act + String result = coupleService.registerEligibleCoupleTracking(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ect details saved: 1", result); + verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING"); + verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + } + + @Test + void registerEligibleCouple_nullIncentiveActivity_noRecordCreated() { + // Arrange + EligibleCoupleDTO dto = new EligibleCoupleDTO(); + dto.setBenId(1L); + dto.setNumLiveChildren(1); + dto.setMarriageFirstChildGap(3); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); + existingECR.setId(1L); + existingECR.setNumLiveChildren(0); + + when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) + .thenReturn(null); + when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + + // Act + String result = coupleService.registerEligibleCouple(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ecr details saved: 1", result); + verify(incentivesRepo).findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING"); + verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + } + + @Test + void registerEligibleCouple_existingECRNullNumLiveChildren_newRecord() { + // Arrange + EligibleCoupleDTO dto = new EligibleCoupleDTO(); + dto.setBenId(1L); + dto.setNumLiveChildren(1); + dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); + dto.setCreatedBy("testUser"); + List dtoList = Arrays.asList(dto); + + EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); + existingECR.setId(1L); + existingECR.setNumLiveChildren(null); // null numLiveChildren should trigger new record creation + + when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); + when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); + when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); + + // Act + String result = coupleService.registerEligibleCouple(dtoList); + + // Assert + assertNotNull(result); + assertEquals("no of ecr details saved: 1", result); + // Should not call incentive methods because numLiveChildren is null + verify(incentivesRepo, never()).findIncentiveMasterByNameAndGroup(anyString(), anyString()); + verify(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java new file mode 100644 index 000000000..cad9270d2 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java @@ -0,0 +1,164 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.domain.iemr.CDR; +import com.iemr.flw.domain.iemr.MDSR; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.CdrDTO; +import com.iemr.flw.dto.iemr.MdsrDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.CdrRepo; +import com.iemr.flw.repo.iemr.MdsrRepo; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.sql.Timestamp; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class DeathReportsServiceImplTest { + @Mock + private CdrRepo cdrRepo; + @Mock + private MdsrRepo mdsrRepo; + @Mock + private BeneficiaryRepo beneficiaryRepo; + @Mock + private ObjectMapper mapper; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private DeathReportsServiceImpl deathReportsService; + + @Test + void registerCDR_new_success() { + CdrDTO dto = new CdrDTO(); + dto.setBenId(1L); + List dtos = Collections.singletonList(dto); + when(cdrRepo.findCDRByBenId(1L)).thenReturn(null); + doNothing().when(modelMapper).map(any(CdrDTO.class), any(CDR.class)); + String result = deathReportsService.registerCDR(dtos); + assertTrue(result.contains("no of cdr details saved: 1")); + } + + @Test + void registerCDR_existing_success() { + CdrDTO dto = new CdrDTO(); + dto.setBenId(2L); + List dtos = Collections.singletonList(dto); + CDR existing = new CDR(); + existing.setId(99L); + when(cdrRepo.findCDRByBenId(2L)).thenReturn(existing); + doNothing().when(modelMapper).map(any(CdrDTO.class), any(CDR.class)); + String result = deathReportsService.registerCDR(dtos); + assertTrue(result.contains("no of cdr details saved: 1")); + } + + @Test + void registerCDR_exception() { + CdrDTO dto = new CdrDTO(); + dto.setBenId(3L); + List dtos = Collections.singletonList(dto); + when(cdrRepo.findCDRByBenId(3L)).thenThrow(new RuntimeException("fail")); + String result = deathReportsService.registerCDR(dtos); + assertTrue(result.startsWith("error while saving cdr details:")); + } + + @Test + void registerMDSR_new_success() { + MdsrDTO dto = new MdsrDTO(); + dto.setBenId(1L); + List dtos = Collections.singletonList(dto); + when(mdsrRepo.findMDSRByBenId(1L)).thenReturn(null); + doNothing().when(modelMapper).map(any(MdsrDTO.class), any(MDSR.class)); + String result = deathReportsService.registerMDSR(dtos); + assertTrue(result.contains("no of mdsr details saved: 1")); + } + + @Test + void registerMDSR_existing_success() { + MdsrDTO dto = new MdsrDTO(); + dto.setBenId(2L); + List dtos = Collections.singletonList(dto); + MDSR existing = new MDSR(); + existing.setId(99L); + when(mdsrRepo.findMDSRByBenId(2L)).thenReturn(existing); + doNothing().when(modelMapper).map(any(MdsrDTO.class), any(MDSR.class)); + String result = deathReportsService.registerMDSR(dtos); + assertTrue(result.contains("no of mdsr details saved: 1")); + } + + @Test + void registerMDSR_exception() { + MdsrDTO dto = new MdsrDTO(); + dto.setBenId(3L); + List dtos = Collections.singletonList(dto); + when(mdsrRepo.findMDSRByBenId(3L)).thenThrow(new RuntimeException("fail")); + String result = deathReportsService.registerMDSR(dtos); + assertTrue(result.startsWith("error while saving mdsr details:")); + } + + @Test + void getCdrRecords_success() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(dto.getAshaId()).thenReturn(ashaId); + when(dto.getFromDate()).thenReturn(fromDate); + when(dto.getToDate()).thenReturn(toDate); + when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); + List cdrList = Arrays.asList(new CDR(), new CDR()); + when(cdrRepo.getAllCdrByBenId("user1", fromDate, toDate)).thenReturn(cdrList); + when(mapper.convertValue(any(CDR.class), eq(CdrDTO.class))).thenReturn(new CdrDTO()); + List result = deathReportsService.getCdrRecords(dto); + assertNotNull(result); + assertEquals(2, result.size()); + } + + @Test + void getCdrRecords_exception() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + when(dto.getAshaId()).thenReturn(ashaId); + when(beneficiaryRepo.getUserName(ashaId)).thenThrow(new RuntimeException("fail")); + List result = deathReportsService.getCdrRecords(dto); + assertNull(result); + } + + @Test + void getMdsrRecords_success() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(dto.getAshaId()).thenReturn(ashaId); + when(dto.getFromDate()).thenReturn(fromDate); + when(dto.getToDate()).thenReturn(toDate); + when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); + List mdsrList = Arrays.asList(new MDSR(), new MDSR()); + when(mdsrRepo.getAllMdsrByAshaId("user1", fromDate, toDate)).thenReturn(mdsrList); + when(mapper.convertValue(any(MDSR.class), eq(MdsrDTO.class))).thenReturn(new MdsrDTO()); + List result = deathReportsService.getMdsrRecords(dto); + assertNotNull(result); + assertEquals(2, result.size()); + } + + @Test + void getMdsrRecords_exception() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + when(dto.getAshaId()).thenReturn(ashaId); + when(beneficiaryRepo.getUserName(ashaId)).thenThrow(new RuntimeException("fail")); + List result = deathReportsService.getMdsrRecords(dto); + assertNull(result); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImplTest.java new file mode 100644 index 000000000..c70c92e57 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImplTest.java @@ -0,0 +1,91 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.DeliveryOutcome; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.DeliveryOutcomeDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.DeliveryOutcomeRepo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +class DeliveryOutcomeServiceImplTest { + @Mock + private DeliveryOutcomeRepo deliveryOutcomeRepo; + @Mock + private BeneficiaryRepo beneficiaryRepo; + + @InjectMocks + private DeliveryOutcomeServiceImpl service; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void registerDeliveryOutcome_newAndExisting() { + DeliveryOutcomeDTO dto1 = new DeliveryOutcomeDTO(); + dto1.setBenId(1L); + DeliveryOutcomeDTO dto2 = new DeliveryOutcomeDTO(); + dto2.setBenId(2L); + List dtos = Arrays.asList(dto1, dto2); + DeliveryOutcome existing = new DeliveryOutcome(); + existing.setId(99L); + when(deliveryOutcomeRepo.findDeliveryOutcomeByBenIdAndIsActive(1L, true)).thenReturn(null); + when(deliveryOutcomeRepo.findDeliveryOutcomeByBenIdAndIsActive(2L, true)).thenReturn(existing); + String result = service.registerDeliveryOutcome(dtos); + assertTrue(result.contains("no of delivery outcome details saved: 2")); + verify(deliveryOutcomeRepo).saveAll(anyList()); + } + + @Test + void registerDeliveryOutcome_exception() { + DeliveryOutcomeDTO dto = new DeliveryOutcomeDTO(); + dto.setBenId(1L); + List dtos = Collections.singletonList(dto); + when(deliveryOutcomeRepo.findDeliveryOutcomeByBenIdAndIsActive(1L, true)).thenReturn(null); + when(deliveryOutcomeRepo.saveAll(anyList())).thenThrow(new RuntimeException("Database error")); + String result = service.registerDeliveryOutcome(dtos); + assertTrue(result.startsWith("error while saving delivery outcome details:")); + } + + @Test + void getDeliveryOutcome_success() { + GetBenRequestHandler req = new GetBenRequestHandler(); + req.setAshaId(123); + Timestamp from = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp to = Timestamp.valueOf("2023-12-31 00:00:00"); + req.setFromDate(from); + req.setToDate(to); + when(beneficiaryRepo.getUserName(123)).thenReturn("user"); + DeliveryOutcome outcome = new DeliveryOutcome(); + when(deliveryOutcomeRepo.getDeliveryOutcomeByAshaId("user", from, to)).thenReturn(Collections.singletonList(outcome)); + List result = service.getDeliveryOutcome(req); + assertNotNull(result); + assertEquals(1, result.size()); + } + + @Test + void getDeliveryOutcome_exception() { + GetBenRequestHandler req = new GetBenRequestHandler(); + req.setAshaId(123); + Timestamp from = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp to = Timestamp.valueOf("2023-12-31 00:00:00"); + req.setFromDate(from); + req.setToDate(to); + when(beneficiaryRepo.getUserName(123)).thenReturn("user"); + when(deliveryOutcomeRepo.getDeliveryOutcomeByAshaId(anyString(), any(Timestamp.class), any(Timestamp.class))).thenThrow(new RuntimeException("fail")); + List result = service.getDeliveryOutcome(req); + assertNull(result); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/HRNonPregnantServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/HRNonPregnantServiceImplTest.java new file mode 100644 index 000000000..d17f2bbf4 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/HRNonPregnantServiceImplTest.java @@ -0,0 +1,197 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.NonPregnantWomanHighRiskAssess; +import com.iemr.flw.domain.iemr.NonPregnantWomanHighRiskTrack; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.HRNonPregnantAssessDTO; +import com.iemr.flw.dto.iemr.HRNonPregnantTrackDTO; +import com.iemr.flw.dto.iemr.HRPregnantAssessDTO; +import com.iemr.flw.dto.iemr.UserDataDTO; +import com.iemr.flw.repo.iemr.HRNonPregnantAssessRepo; +import com.iemr.flw.repo.iemr.HRNonPregnantTrackRepo; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.sql.Timestamp; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class HRNonPregnantServiceImplTest { + @Mock + private HRNonPregnantAssessRepo assessRepo; + @Mock + private HRNonPregnantTrackRepo trackRepo; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private HRNonPregnantServiceImpl service; + + @Test + void getAllAssessment_success() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + List entityList = Arrays.asList(new NonPregnantWomanHighRiskAssess(), new NonPregnantWomanHighRiskAssess()); + when(assessRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(entityList); + String json = service.getAllAssessment(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(2, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void getAllAssessment_emptyList() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + when(assessRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); + String json = service.getAllAssessment(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(0, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void saveAllAssessment_newAssess_success() { + HRNonPregnantAssessDTO dto = new HRNonPregnantAssessDTO(); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(10); + req.setEntries(Collections.singletonList(dto)); + HRPregnantAssessDTO mapped = new HRPregnantAssessDTO(); + mapped.setBenId(1L); + when(assessRepo.getByUserIdAndBenId(isNull(), eq(10))).thenReturn(null); + // No need to stub assessRepo.save for void/irrelevant methods + String result = service.saveAllAssessment(req); + assertTrue(result.contains("no of high risk assessment items saved: 1")); + } + + @Test + void saveAllAssessment_existingAssess_success() { + HRNonPregnantAssessDTO dto = new HRNonPregnantAssessDTO(); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(20); + req.setEntries(Collections.singletonList(dto)); + HRPregnantAssessDTO mapped = new HRPregnantAssessDTO(); + mapped.setBenId(2L); + NonPregnantWomanHighRiskAssess existing = new NonPregnantWomanHighRiskAssess(); + existing.setId(99L); + + when(assessRepo.getByUserIdAndBenId(isNull(), eq(20))).thenReturn(existing); + // No need to stub assessRepo.save for void/irrelevant methods + String result = service.saveAllAssessment(req); + assertTrue(result.contains("no of high risk assessment items saved: 1")); + } + + @Test + void saveAllAssessment_exception() { + HRNonPregnantAssessDTO dto = new HRNonPregnantAssessDTO(); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(30); + req.setEntries(Collections.singletonList(dto)); + HRPregnantAssessDTO mapped = new HRPregnantAssessDTO(); + mapped.setBenId(3L); + when(modelMapper.map(dto, HRPregnantAssessDTO.class)).thenReturn(mapped); + when(assessRepo.getByUserIdAndBenId(3L, 30)).thenThrow(new RuntimeException("fail")); + assertThrows(RuntimeException.class, () -> service.saveAllAssessment(req)); + } + + @Test + void getAllTracking_success() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + List entityList = Arrays.asList(new NonPregnantWomanHighRiskTrack(), new NonPregnantWomanHighRiskTrack()); + when(trackRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(entityList); + String json = service.getAllTracking(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(2, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void getAllTracking_emptyList() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + when(trackRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); + String json = service.getAllTracking(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(0, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void saveAllTracking_newTrack_success() { + HRNonPregnantTrackDTO dto = new HRNonPregnantTrackDTO(); + dto.setBenId(1L); + dto.setVisitDate(new java.sql.Timestamp(System.currentTimeMillis())); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(10); + req.setEntries(Collections.singletonList(dto)); + when(trackRepo.getByUserIdAndBenId(dto.getBenId(), 10, dto.getVisitDate())).thenReturn(null); + when(trackRepo.save(any(NonPregnantWomanHighRiskTrack.class))).thenReturn(new NonPregnantWomanHighRiskTrack()); + String result = service.saveAllTracking(req); + assertTrue(result.contains("no of high risk pregnant tracking items saved: 1")); + } + + @Test + void saveAllTracking_existingTrack_success() { + HRNonPregnantTrackDTO dto = new HRNonPregnantTrackDTO(); + dto.setBenId(2L); + dto.setVisitDate(new java.sql.Timestamp(System.currentTimeMillis())); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(20); + req.setEntries(Collections.singletonList(dto)); + NonPregnantWomanHighRiskTrack existing = new NonPregnantWomanHighRiskTrack(); + existing.setId(99L); + when(trackRepo.getByUserIdAndBenId(dto.getBenId(), 20, dto.getVisitDate())).thenReturn(existing); + + when(trackRepo.save(any(NonPregnantWomanHighRiskTrack.class))).thenReturn(existing); + String result = service.saveAllTracking(req); + assertTrue(result.contains("no of high risk pregnant tracking items saved: 1")); + } + + @Test + void saveAllTracking_exception() { + HRNonPregnantTrackDTO dto = new HRNonPregnantTrackDTO(); + dto.setBenId(3L); + dto.setVisitDate(new java.sql.Timestamp(System.currentTimeMillis())); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(30); + req.setEntries(Collections.singletonList(dto)); + // No need to stub assessRepo.getByUserIdAndBenId for this test + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/HRPregnantServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/HRPregnantServiceImplTest.java new file mode 100644 index 000000000..08a4fe35c --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/HRPregnantServiceImplTest.java @@ -0,0 +1,190 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.PregnantWomanHighRiskAssess; +import com.iemr.flw.domain.iemr.PregnantWomanHighRiskTrack; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.HRPregnantAssessDTO; +import com.iemr.flw.dto.iemr.HRPregnantTrackDTO; +import com.iemr.flw.dto.iemr.UserDataDTO; +import com.iemr.flw.repo.iemr.HRPregnantAssessRepo; +import com.iemr.flw.repo.iemr.HRPregnantTrackRepo; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.sql.Timestamp; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class HRPregnantServiceImplTest { + @Mock + private HRPregnantAssessRepo assessRepo; + @Mock + private HRPregnantTrackRepo trackRepo; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private HRPregnantServiceImpl service; + + @Test + void getAllAssessments_success() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + List entityList = Arrays.asList(new PregnantWomanHighRiskAssess(), new PregnantWomanHighRiskAssess()); + when(assessRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(entityList); + String json = service.getAllAssessments(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(2, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void getAllAssessments_emptyList() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + when(assessRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); + String json = service.getAllAssessments(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(0, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void saveAllAssessment_newAssess_success() { + HRPregnantAssessDTO dto = new HRPregnantAssessDTO(); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(10); + req.setEntries(Collections.singletonList(dto)); + HRPregnantAssessDTO mapped = new HRPregnantAssessDTO(); + mapped.setBenId(1L); + when(assessRepo.getByUserIdAndBenId(isNull(), eq(10))).thenReturn(null); + String result = service.saveAllAssessment(req); + assertTrue(result.contains("no of high risk assessment items saved: 1")); + } + + @Test + void saveAllAssessment_existingAssess_success() { + HRPregnantAssessDTO dto = new HRPregnantAssessDTO(); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(20); + req.setEntries(Collections.singletonList(dto)); + HRPregnantAssessDTO mapped = new HRPregnantAssessDTO(); + mapped.setBenId(2L); + PregnantWomanHighRiskAssess existing = new PregnantWomanHighRiskAssess(); + existing.setId(99L); + when(assessRepo.getByUserIdAndBenId(isNull(), eq(20))).thenReturn(existing); + String result = service.saveAllAssessment(req); + assertTrue(result.contains("no of high risk assessment items saved: 1")); + } + + @Test + void saveAllAssessment_exception() { + HRPregnantAssessDTO dto = new HRPregnantAssessDTO(); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(30); + req.setEntries(Collections.singletonList(dto)); + HRPregnantAssessDTO mapped = new HRPregnantAssessDTO(); + mapped.setBenId(3L); + when(assessRepo.getByUserIdAndBenId(isNull(), eq(30))).thenThrow(new RuntimeException("fail")); + assertThrows(RuntimeException.class, () -> service.saveAllAssessment(req)); + } + + @Test + void getAllTracking_success() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + List entityList = Arrays.asList(new PregnantWomanHighRiskTrack(), new PregnantWomanHighRiskTrack()); + when(trackRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(entityList); + String json = service.getAllTracking(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(2, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void getAllTracking_emptyList() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + when(trackRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); + String json = service.getAllTracking(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(0, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void saveAllTracking_newTrack_success() { + HRPregnantTrackDTO dto = new HRPregnantTrackDTO(); + dto.setBenId(1L); + dto.setVisit("2023-08-16"); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(10); + req.setEntries(Collections.singletonList(dto)); + when(trackRepo.getByUserIdAndBenId(dto.getBenId(), 10, dto.getVisit())).thenReturn(null); + String result = service.saveAllTracking(req); + assertTrue(result.contains("no of high risk pregnant tracking items saved: 1")); + } + + @Test + void saveAllTracking_existingTrack_success() { + HRPregnantTrackDTO dto = new HRPregnantTrackDTO(); + dto.setBenId(2L); + dto.setVisit("2023-08-16"); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(20); + req.setEntries(Collections.singletonList(dto)); + PregnantWomanHighRiskTrack existing = new PregnantWomanHighRiskTrack(); + existing.setId(99L); + when(trackRepo.getByUserIdAndBenId(dto.getBenId(), 20, dto.getVisit())).thenReturn(existing); + String result = service.saveAllTracking(req); + assertTrue(result.contains("no of high risk pregnant tracking items saved: 1")); + } + + @Test + void saveAllTracking_exception() { + HRPregnantTrackDTO dto = new HRPregnantTrackDTO(); + dto.setBenId(3L); + dto.setVisit("2023-08-16"); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(30); + req.setEntries(Collections.singletonList(dto)); + when(trackRepo.getByUserIdAndBenId(dto.getBenId(), 30, dto.getVisit())).thenThrow(new RuntimeException("fail")); + assertThrows(RuntimeException.class, () -> service.saveAllTracking(req)); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/HighRiskServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/HighRiskServiceImplTest.java new file mode 100644 index 000000000..e440d6206 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/HighRiskServiceImplTest.java @@ -0,0 +1,114 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.HighRiskAssess; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.HighRiskAssessDTO; +import com.iemr.flw.dto.iemr.UserDataDTO; +import com.iemr.flw.repo.iemr.HighRiskAssessRepo; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.sql.Timestamp; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class HighRiskServiceImplTest { + @Mock + private HighRiskAssessRepo assessRepo; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private HighRiskServiceImpl highRiskService; + + @Test + void getAllAssessments_success() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + List entityList = Arrays.asList(new HighRiskAssess(), new HighRiskAssess()); + when(assessRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(entityList); + String json = highRiskService.getAllAssessments(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(2, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void getAllAssessments_emptyList() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + when(assessRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); + String json = highRiskService.getAllAssessments(req); + assertNotNull(json); + java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken>(){}.getType(); + UserDataDTO result = new Gson().fromJson(json, type); + assertEquals(0, result.getEntries().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void saveAllAssessment_newAssess_success() { + HighRiskAssessDTO dto = new HighRiskAssessDTO(); + dto.setBenId(1L); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(10); + req.setEntries(Collections.singletonList(dto)); + HighRiskAssess mapped = new HighRiskAssess(); + mapped.setBenId(1L); + // No need to stub modelMapper.map(dto, HighRiskAssessDTO.class) as its result is not used + when(assessRepo.getByUserIdAndBenId(1L, 10)).thenReturn(null); + when(assessRepo.save(any(HighRiskAssess.class))).thenReturn(new HighRiskAssess()); + String result = highRiskService.saveAllAssessment(req); + assertTrue(result.contains("no of high risk assessment items saved: 1")); + } + + @Test + void saveAllAssessment_existingAssess_success() { + HighRiskAssessDTO dto = new HighRiskAssessDTO(); + dto.setBenId(2L); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(20); + req.setEntries(Collections.singletonList(dto)); + HighRiskAssess mapped = new HighRiskAssess(); + mapped.setBenId(2L); + HighRiskAssess existing = new HighRiskAssess(); + existing.setId(99L); + // No need to stub modelMapper.map(dto, HighRiskAssessDTO.class) as its result is not used + when(assessRepo.getByUserIdAndBenId(2L, 20)).thenReturn(existing); + when(assessRepo.save(any(HighRiskAssess.class))).thenReturn(existing); + String result = highRiskService.saveAllAssessment(req); + assertTrue(result.contains("no of high risk assessment items saved: 1")); + } + + @Test + void saveAllAssessment_exception() { + HighRiskAssessDTO dto = new HighRiskAssessDTO(); + dto.setBenId(3L); + UserDataDTO req = new UserDataDTO<>(); + req.setUserId(30); + req.setEntries(Collections.singletonList(dto)); + // No need to stub modelMapper.map(dto, HighRiskAssessDTO.class) as its result is not used + when(assessRepo.getByUserIdAndBenId(3L, 30)).thenThrow(new RuntimeException("fail")); + assertThrows(RuntimeException.class, () -> highRiskService.saveAllAssessment(req)); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/IncentiveServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/IncentiveServiceImplTest.java new file mode 100644 index 000000000..1038f1330 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/IncentiveServiceImplTest.java @@ -0,0 +1,128 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.IncentiveActivity; +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.repo.iemr.IncentiveRecordRepo; +import com.iemr.flw.repo.iemr.IncentivesRepo; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.sql.Timestamp; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class IncentiveServiceImplTest { + @Mock + private IncentivesRepo incentivesRepo; + @Mock + private IncentiveRecordRepo recordRepo; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private IncentiveServiceImpl incentiveService; + + @Test + void saveIncentivesMaster_newActivity_success() { + IncentiveActivityDTO dto = new IncentiveActivityDTO(); + dto.setName("TestName"); + dto.setGroup("TestGroup"); + List dtos = Collections.singletonList(dto); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("TestName", "TestGroup")).thenReturn(null); + doNothing().when(modelMapper).map(any(IncentiveActivityDTO.class), any(IncentiveActivity.class)); + when(incentivesRepo.save(any(IncentiveActivity.class))).thenReturn(new IncentiveActivity()); + String result = incentiveService.saveIncentivesMaster(dtos); + assertNotNull(result); + assertTrue(result.contains("saved master data for")); + } + + @Test + void saveIncentivesMaster_existingActivity_success() { + IncentiveActivityDTO dto = new IncentiveActivityDTO(); + dto.setName("TestName2"); + dto.setGroup("TestGroup2"); + List dtos = Collections.singletonList(dto); + IncentiveActivity existing = new IncentiveActivity(); + existing.setId(99L); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("TestName2", "TestGroup2")).thenReturn(existing); + doNothing().when(modelMapper).map(any(IncentiveActivityDTO.class), any(IncentiveActivity.class)); + when(incentivesRepo.save(any(IncentiveActivity.class))).thenReturn(existing); + String result = incentiveService.saveIncentivesMaster(dtos); + assertNotNull(result); + assertTrue(result.contains("saved master data for")); + } + + @Test + void saveIncentivesMaster_exception() { + IncentiveActivityDTO dto = new IncentiveActivityDTO(); + dto.setName("TestName3"); + dto.setGroup("TestGroup3"); + List dtos = Collections.singletonList(dto); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("TestName3", "TestGroup3")).thenThrow(new RuntimeException("fail")); + String result = incentiveService.saveIncentivesMaster(dtos); + assertNull(result); + } + + @Test + void getIncentiveMaster_success() { + IncentiveActivity activity = new IncentiveActivity(); + List activities = Arrays.asList(activity, activity); + when(incentivesRepo.findAll()).thenReturn(activities); + when(modelMapper.map(any(IncentiveActivity.class), eq(IncentiveActivityDTO.class))).thenReturn(new IncentiveActivityDTO()); + String json = incentiveService.getIncentiveMaster(new IncentiveRequestDTO()); + assertNotNull(json); + IncentiveActivityDTO[] arr = new Gson().fromJson(json, IncentiveActivityDTO[].class); + assertEquals(2, arr.length); + } + + @Test + void getIncentiveMaster_exception() { + when(incentivesRepo.findAll()).thenThrow(new RuntimeException("fail")); + String result = incentiveService.getIncentiveMaster(new IncentiveRequestDTO()); + assertNull(result); + } + + @Test + void getAllIncentivesByUserId_success() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + List entities = Arrays.asList(new IncentiveActivityRecord(), new IncentiveActivityRecord()); + when(recordRepo.findRecordsByAsha(ashaId, fromDate, toDate)).thenReturn(entities); + when(modelMapper.map(any(IncentiveActivityRecord.class), eq(IncentiveRecordDTO.class))).thenReturn(new IncentiveRecordDTO()); + String json = incentiveService.getAllIncentivesByUserId(req); + assertNotNull(json); + IncentiveRecordDTO[] arr = new Gson().fromJson(json, IncentiveRecordDTO[].class); + assertEquals(2, arr.length); + } + + @Test + void getAllIncentivesByUserId_emptyList() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + when(recordRepo.findRecordsByAsha(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); + String json = incentiveService.getAllIncentivesByUserId(req); + assertNotNull(json); + IncentiveRecordDTO[] arr = new Gson().fromJson(json, IncentiveRecordDTO[].class); + assertEquals(0, arr.length); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/InfantServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/InfantServiceImplTest.java new file mode 100644 index 000000000..86772faf4 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/InfantServiceImplTest.java @@ -0,0 +1,101 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.domain.iemr.InfantRegister; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.InfantRegisterDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.InfantRegisterRepo; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.sql.Timestamp; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class InfantServiceImplTest { + @Mock + private InfantRegisterRepo infantRegisterRepo; + @Mock + private BeneficiaryRepo beneficiaryRepo; + @Mock + private ObjectMapper mapper; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private InfantServiceImpl infantService; + + @Test + void registerInfant_newInfant_success() { + InfantRegisterDTO dto = new InfantRegisterDTO(); + dto.setBenId(1L); + dto.setBabyIndex(1); + List dtos = Collections.singletonList(dto); + when(infantRegisterRepo.findInfantRegisterByBenIdAndBabyIndexAndIsActive(1L, 1, true)).thenReturn(null); + doNothing().when(modelMapper).map(any(InfantRegisterDTO.class), any(InfantRegister.class)); + String result = infantService.registerInfant(dtos); + assertTrue(result.contains("no of infant register details saved: 1")); + } + + @Test + void registerInfant_existingInfant_success() { + InfantRegisterDTO dto = new InfantRegisterDTO(); + dto.setBenId(2L); + dto.setBabyIndex(2); + List dtos = Collections.singletonList(dto); + InfantRegister existing = new InfantRegister(); + existing.setId(99L); + when(infantRegisterRepo.findInfantRegisterByBenIdAndBabyIndexAndIsActive(2L, 2, true)).thenReturn(existing); + doNothing().when(modelMapper).map(any(InfantRegisterDTO.class), any(InfantRegister.class)); + + String result = infantService.registerInfant(dtos); + assertTrue(result.contains("no of infant register details saved: 1")); + } + + @Test + void registerInfant_exception() { + InfantRegisterDTO dto = new InfantRegisterDTO(); + dto.setBenId(3L); + dto.setBabyIndex(3); + List dtos = Collections.singletonList(dto); + when(infantRegisterRepo.findInfantRegisterByBenIdAndBabyIndexAndIsActive(3L, 3, true)).thenThrow(new RuntimeException("fail")); + String result = infantService.registerInfant(dtos); + assertNull(result); + } + + @Test + void getInfantDetails_success() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(dto.getAshaId()).thenReturn(ashaId); + when(dto.getFromDate()).thenReturn(fromDate); + when(dto.getToDate()).thenReturn(toDate); + when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); + List infantList = Arrays.asList(new InfantRegister(), new InfantRegister()); + when(infantRegisterRepo.getInfantDetailsForUser("user1", fromDate, toDate)).thenReturn(infantList); + when(mapper.convertValue(any(InfantRegister.class), eq(InfantRegisterDTO.class))).thenReturn(new InfantRegisterDTO()); + List result = infantService.getInfantDetails(dto); + assertNotNull(result); + assertEquals(2, result.size()); + } + + @Test + void getInfantDetails_exception() { + GetBenRequestHandler dto = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + when(dto.getAshaId()).thenReturn(ashaId); + when(beneficiaryRepo.getUserName(ashaId)).thenThrow(new RuntimeException("fail")); + List result = infantService.getInfantDetails(dto); + assertNull(result); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java new file mode 100644 index 000000000..fab5c2861 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java @@ -0,0 +1,632 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class MaternalHealthServiceImplTest { + + @Mock + private PregnantWomanRegisterRepo pregnantWomanRegisterRepo; + @Mock + private ANCVisitRepo ancVisitRepo; + @Mock + private AncCareRepo ancCareRepo; + @Mock + private PNCVisitRepo pncVisitRepo; + @Mock + private PNCCareRepo pncCareRepo; + @Mock + private BenVisitDetailsRepo benVisitDetailsRepo; + @Mock + private BeneficiaryRepo beneficiaryRepo; + @Mock + private PmsmaRepo pmsmaRepo; + @Mock + private IncentivesRepo incentivesRepo; + @Mock + private UserServiceRoleRepo userRepo; + @Mock + private IncentiveRecordRepo recordRepo; + + @InjectMocks + private MaternalHealthServiceImpl service; + + private Timestamp currentTime; + + @BeforeEach + void setUp() { + currentTime = Timestamp.from(Instant.now()); + } + + // registerPregnantWoman tests + @Test + void testRegisterPregnantWoman_newRecord_success() { + // Arrange + PregnantWomanDTO dto = createPregnantWomanDTO(); + PregnantWomanRegister savedRegister = new PregnantWomanRegister(); + savedRegister.setId(1L); + + when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) + .thenReturn(null); + when(pregnantWomanRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedRegister)); + + // Act + String result = service.registerPregnantWoman(Arrays.asList(dto)); + + // Assert + assertEquals("no of pwr details saved: 1", result); + verify(pregnantWomanRegisterRepo).findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true); + verify(pregnantWomanRegisterRepo).saveAll(anyList()); + } + + @Test + void testRegisterPregnantWoman_existingRecord_success() { + // Arrange + PregnantWomanDTO dto = createPregnantWomanDTO(); + PregnantWomanRegister existingRegister = new PregnantWomanRegister(); + existingRegister.setId(5L); + + when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) + .thenReturn(existingRegister); + when(pregnantWomanRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingRegister)); + + // Act + String result = service.registerPregnantWoman(Arrays.asList(dto)); + + // Assert + assertEquals("no of pwr details saved: 1", result); + verify(pregnantWomanRegisterRepo).findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true); + verify(pregnantWomanRegisterRepo).saveAll(anyList()); + } + + @Test + void testRegisterPregnantWoman_exception() { + // Arrange + PregnantWomanDTO dto = createPregnantWomanDTO(); + when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = service.registerPregnantWoman(Arrays.asList(dto)); + + // Assert + assertNull(result); + } + + // getPregnantWoman tests + @Test + void testGetPregnantWoman_success() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + String userName = "testUser"; + PregnantWomanRegister register = new PregnantWomanRegister(); + register.setId(1L); + register.setBenId(123L); + + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); + when(pregnantWomanRegisterRepo.getPWRWithBen(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(register)); + + // Act + List result = service.getPregnantWoman(dto); + + // Assert + assertNotNull(result); + assertEquals(1, result.size()); + verify(beneficiaryRepo).getUserName(dto.getAshaId()); + verify(pregnantWomanRegisterRepo).getPWRWithBen(userName, dto.getFromDate(), dto.getToDate()); + } + + @Test + void testGetPregnantWoman_exception() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); + + // Act + List result = service.getPregnantWoman(dto); + + // Assert + assertNull(result); + } + + // getANCVisits tests + @Test + void testGetANCVisits_success() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + String userName = "testUser"; + ANCVisit ancVisit = new ANCVisit(); + ancVisit.setId(1L); + ancVisit.setBenId(123L); + + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); + when(ancVisitRepo.getANCForPW(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(ancVisit)); + + // Act + List result = service.getANCVisits(dto); + + // Assert + assertNotNull(result); + assertEquals(1, result.size()); + verify(beneficiaryRepo).getUserName(dto.getAshaId()); + verify(ancVisitRepo).getANCForPW(userName, dto.getFromDate(), dto.getToDate()); + } + + @Test + void testGetANCVisits_exception() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); + + // Act + List result = service.getANCVisits(dto); + + // Assert + assertNull(result); + } + + // saveANCVisit tests + @Test + void testSaveANCVisit_newRecord_success() { + // Arrange + ANCVisitDTO dto = createANCVisitDTO(); + BenVisitDetail savedVisitDetail = new BenVisitDetail(); + savedVisitDetail.setBenVisitId(1L); + + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) + .thenReturn(null); + when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); + when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) + .thenReturn(null); + when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); + when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new ANCVisit())); + when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); + + // Act + String result = service.saveANCVisit(Arrays.asList(dto)); + + // Assert + assertEquals("no of anc details saved: 1", result); + verify(ancVisitRepo).findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true); + verify(beneficiaryRepo).getRegIDFromBenId(dto.getBenId()); + verify(benVisitDetailsRepo).save(any(BenVisitDetail.class)); + verify(ancVisitRepo).saveAll(anyList()); + verify(ancCareRepo).saveAll(anyList()); + } + + @Test + void testSaveANCVisit_newRecordWithPregnantWomanRegister_success() { + // Arrange + ANCVisitDTO dto = createANCVisitDTO(); + PregnantWomanRegister pwr = new PregnantWomanRegister(); + pwr.setLmpDate(currentTime); + BenVisitDetail savedVisitDetail = new BenVisitDetail(); + savedVisitDetail.setBenVisitId(1L); + + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) + .thenReturn(null); + when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); + when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) + .thenReturn(pwr); + when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); + when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new ANCVisit())); + when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); + + // Act + String result = service.saveANCVisit(Arrays.asList(dto)); + + // Assert + assertEquals("no of anc details saved: 1", result); + } + + @Test + void testSaveANCVisit_existingRecord_success() { + // Arrange + ANCVisitDTO dto = createANCVisitDTO(); + ANCVisit existingVisit = new ANCVisit(); + existingVisit.setId(5L); + + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) + .thenReturn(existingVisit); + when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); + when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + + // Act + String result = service.saveANCVisit(Arrays.asList(dto)); + + // Assert + assertEquals("no of anc details saved: 1", result); + verify(ancVisitRepo).findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true); + verify(ancVisitRepo).saveAll(anyList()); + } + + @Test + void testSaveANCVisit_withIncentives_anc1() { + // Arrange + ANCVisitDTO dto = createANCVisitDTO(); + dto.setAncVisit(1); // First ANC visit + BenVisitDetail savedVisitDetail = new BenVisitDetail(); + savedVisitDetail.setBenVisitId(1L); + + ANCVisit savedAncVisit = new ANCVisit(); + savedAncVisit.setAncVisit(1); + savedAncVisit.setBenId(dto.getBenId()); + savedAncVisit.setCreatedDate(currentTime); + savedAncVisit.setCreatedBy("testUser"); + + IncentiveActivity anc1Activity = new IncentiveActivity(); + anc1Activity.setId(1L); + anc1Activity.setRate(100); + + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) + .thenReturn(null); + when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); + when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) + .thenReturn(null); + when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); + when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedAncVisit)); + when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-1", "MATERNAL HEALTH")) + .thenReturn(anc1Activity); + when(userRepo.getUserIdByName("testUser")).thenReturn(1); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, dto.getBenId())) + .thenReturn(null); + + // Act + String result = service.saveANCVisit(Arrays.asList(dto)); + + // Assert + assertEquals("no of anc details saved: 1", result); + verify(recordRepo).save(any(IncentiveActivityRecord.class)); + } + + @Test + void testSaveANCVisit_withIncentives_anc4() { + // Arrange + ANCVisitDTO dto = createANCVisitDTO(); + dto.setAncVisit(4); // Fourth ANC visit + + ANCVisit existingAncVisit = new ANCVisit(); + existingAncVisit.setId(1L); + existingAncVisit.setAncVisit(4); + existingAncVisit.setBenId(dto.getBenId()); + existingAncVisit.setCreatedDate(currentTime); + existingAncVisit.setCreatedBy("testUser"); + + IncentiveActivity ancFullActivity = new IncentiveActivity(); + ancFullActivity.setId(2L); + ancFullActivity.setRate(200); + + // Create mock ANC visits for all 4 visits + ANCVisit visit1 = new ANCVisit(); + visit1.setCreatedDate(currentTime); + ANCVisit visit2 = new ANCVisit(); + ANCVisit visit3 = new ANCVisit(); + ANCVisit visit4 = new ANCVisit(); + visit4.setCreatedDate(currentTime); + + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) + .thenReturn(existingAncVisit); + when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingAncVisit)); + when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-1", "MATERNAL HEALTH")) + .thenReturn(new IncentiveActivity()); // Need to return a non-null activity for processing to continue + when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-FULL", "MATERNAL HEALTH")) + .thenReturn(ancFullActivity); + when(userRepo.getUserIdByName("testUser")).thenReturn(1); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, dto.getBenId())) + .thenReturn(null); + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 1, true)) + .thenReturn(visit1); + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 2, true)) + .thenReturn(visit2); + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 3, true)) + .thenReturn(visit3); + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 4, true)) + .thenReturn(visit4); + + // Act + String result = service.saveANCVisit(Arrays.asList(dto)); + + // Assert + assertEquals("no of anc details saved: 1", result); + verify(recordRepo).save(any(IncentiveActivityRecord.class)); + } + + @Test + void testSaveANCVisit_exception() { + // Arrange + ANCVisitDTO dto = createANCVisitDTO(); + when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = service.saveANCVisit(Arrays.asList(dto)); + + // Assert + assertNull(result); + } + + // getPmsmaRecords tests + @Test + void testGetPmsmaRecords_success() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + String userName = "testUser"; + PMSMA pmsma = new PMSMA(); + pmsma.setId(1L); + pmsma.setBenId(123L); + + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); + when(pmsmaRepo.getAllPmsmaByAshaId(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(pmsma)); + + // Act + List result = service.getPmsmaRecords(dto); + + // Assert + assertNotNull(result); + assertEquals(1, result.size()); + verify(beneficiaryRepo).getUserName(dto.getAshaId()); + verify(pmsmaRepo).getAllPmsmaByAshaId(userName, dto.getFromDate(), dto.getToDate()); + } + + @Test + void testGetPmsmaRecords_exception() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); + + // Act + List result = service.getPmsmaRecords(dto); + + // Assert + assertNull(result); + } + + // savePmsmaRecords tests + @Test + void testSavePmsmaRecords_newRecord_success() { + // Arrange + PmsmaDTO dto = createPmsmaDTO(); + PMSMA savedPmsma = new PMSMA(); + savedPmsma.setId(1L); + + when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)).thenReturn(null); + when(pmsmaRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedPmsma)); + + // Act + String result = service.savePmsmaRecords(Arrays.asList(dto)); + + // Assert + assertEquals("No. of PMSMA records saved: 1", result); + verify(pmsmaRepo).findPMSMAByBenIdAndIsActive(dto.getBenId(), true); + verify(pmsmaRepo).saveAll(anyList()); + } + + @Test + void testSavePmsmaRecords_existingRecord_success() { + // Arrange + PmsmaDTO dto = createPmsmaDTO(); + PMSMA existingPmsma = new PMSMA(); + existingPmsma.setId(5L); + + when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)).thenReturn(existingPmsma); + when(pmsmaRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingPmsma)); + + // Act + String result = service.savePmsmaRecords(Arrays.asList(dto)); + + // Assert + assertEquals("No. of PMSMA records saved: 1", result); + verify(pmsmaRepo).findPMSMAByBenIdAndIsActive(dto.getBenId(), true); + verify(pmsmaRepo).saveAll(anyList()); + } + + @Test + void testSavePmsmaRecords_exception() { + // Arrange + PmsmaDTO dto = createPmsmaDTO(); + when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = service.savePmsmaRecords(Arrays.asList(dto)); + + // Assert + assertNull(result); + } + + // getPNCVisits tests + @Test + void testGetPNCVisits_success() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + String userName = "testUser"; + PNCVisit pncVisit = new PNCVisit(); + pncVisit.setId(1L); + pncVisit.setBenId(123L); + + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); + when(pncVisitRepo.getPNCForPW(userName, dto.getFromDate(), dto.getToDate())) + .thenReturn(Arrays.asList(pncVisit)); + + // Act + List result = service.getPNCVisits(dto); + + // Assert + assertNotNull(result); + assertEquals(1, result.size()); + verify(beneficiaryRepo).getUserName(dto.getAshaId()); + verify(pncVisitRepo).getPNCForPW(userName, dto.getFromDate(), dto.getToDate()); + } + + @Test + void testGetPNCVisits_exception() { + // Arrange + GetBenRequestHandler dto = createGetBenRequestHandler(); + when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); + + // Act + List result = service.getPNCVisits(dto); + + // Assert + assertNull(result); + } + + // savePNCVisit tests + @Test + void testSavePNCVisit_newRecord_success() { + // Arrange + PNCVisitDTO dto = createPNCVisitDTO(); + BenVisitDetail savedVisitDetail = new BenVisitDetail(); + savedVisitDetail.setBenVisitId(1L); + + when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) + .thenReturn(null); + when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); + when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) + .thenReturn(null); + when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); + when(pncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new PNCVisit())); + when(pncCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new PNCCare())); + + // Act + String result = service.savePNCVisit(Arrays.asList(dto)); + + // Assert + assertEquals("no of pnc details saved: 1", result); + verify(pncVisitRepo).findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true); + verify(beneficiaryRepo).getRegIDFromBenId(dto.getBenId()); + verify(benVisitDetailsRepo).save(any(BenVisitDetail.class)); + verify(pncVisitRepo).saveAll(anyList()); + verify(pncCareRepo).saveAll(anyList()); + } + + @Test + void testSavePNCVisit_existingRecord_success() { + // Arrange + PNCVisitDTO dto = createPNCVisitDTO(); + PNCVisit existingVisit = new PNCVisit(); + existingVisit.setId(5L); + + when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) + .thenReturn(existingVisit); + when(pncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); + when(pncCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); + + // Act + String result = service.savePNCVisit(Arrays.asList(dto)); + + // Assert + assertEquals("no of pnc details saved: 1", result); + verify(pncVisitRepo).findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true); + verify(pncVisitRepo).saveAll(anyList()); + } + + @Test + void testSavePNCVisit_exception() { + // Arrange + PNCVisitDTO dto = createPNCVisitDTO(); + when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) + .thenThrow(new RuntimeException("Database error")); + + // Act + String result = service.savePNCVisit(Arrays.asList(dto)); + + // Assert + assertNull(result); + } + + // Helper methods to create test data + private PregnantWomanDTO createPregnantWomanDTO() { + PregnantWomanDTO dto = new PregnantWomanDTO(); + dto.setBenId(123L); + dto.setLmpDate(currentTime); + dto.setBloodGroup("A+"); + dto.setWeight(60); + dto.setHeight(160); + dto.setIsActive(true); + dto.setCreatedBy("testUser"); + dto.setCreatedDate(currentTime); + dto.setUpdatedBy("testUser"); + dto.setUpdatedDate(currentTime); + return dto; + } + + private GetBenRequestHandler createGetBenRequestHandler() { + GetBenRequestHandler dto = new GetBenRequestHandler(); + dto.setAshaId(1); + dto.setFromDate(currentTime); + dto.setToDate(currentTime); + return dto; + } + + private ANCVisitDTO createANCVisitDTO() { + ANCVisitDTO dto = new ANCVisitDTO(); + dto.setBenId(123L); + dto.setAncDate(currentTime); + dto.setAncVisit(1); + dto.setWeightOfPW(65); + dto.setBpSystolic(120); + dto.setBpDiastolic(80); + dto.setIsActive(true); + dto.setCreatedDate(currentTime); + dto.setCreatedBy("testUser"); + dto.setUpdatedDate(currentTime); + dto.setUpdatedBy("testUser"); + dto.setProviderServiceMapID(1); + return dto; + } + + private PmsmaDTO createPmsmaDTO() { + PmsmaDTO dto = new PmsmaDTO(); + dto.setBenId(123L); + dto.setRchNumber("RCH123"); + dto.setHusbandName("Test Husband"); + dto.setAddress("Test Address"); + dto.setWeight(65); + dto.setIsActive(true); + dto.setCreatedBy("testUser"); + dto.setCreatedDate(currentTime); + dto.setUpdatedDate(currentTime); + dto.setUpdatedBy("testUser"); + return dto; + } + + private PNCVisitDTO createPNCVisitDTO() { + PNCVisitDTO dto = new PNCVisitDTO(); + dto.setBenId(123L); + dto.setPncPeriod(0); // First day + dto.setPncDate(currentTime); + dto.setIfaTabsGiven(10); + dto.setAnyContraceptionMethod(false); + dto.setMotherDeath(false); + dto.setIsActive(true); + dto.setCreatedDate(currentTime); + dto.setCreatedBy("testUser"); + dto.setUpdatedDate(currentTime); + dto.setUpdatedBy("testUser"); + return dto; + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java new file mode 100644 index 000000000..7ee07fbc3 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java @@ -0,0 +1,118 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.TBScreening; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.TBScreeningDTO; +import com.iemr.flw.dto.iemr.TBScreeningRequestDTO; +import com.iemr.flw.repo.iemr.TBScreeningRepo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.modelmapper.ModelMapper; + +import java.sql.Timestamp; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class TBScreeningServiceImplTest { + @Mock + private TBScreeningRepo tbScreeningRepo; + @Mock + private ModelMapper modelMapper; + @InjectMocks + private TBScreeningServiceImpl tbScreeningService; + + @BeforeEach + void setUp() { + // inject mock modelMapper + // Reflection is not needed as modelMapper is final, but we can set via constructor if needed + } + + @Test + void getByBenId_returnsNull() throws Exception { + String result = tbScreeningService.getByBenId(1L, "auth"); + assertNull(result); + } + + @Test + void save_newTBScreening_success() throws Exception { + TBScreeningDTO dto = new TBScreeningDTO(); + dto.setBenId(1L); + TBScreeningRequestDTO req = new TBScreeningRequestDTO(); + req.setUserId(10); + req.setTbScreeningList(Collections.singletonList(dto)); + when(tbScreeningRepo.getByUserIdAndBenId(1L, 10)).thenReturn(null); + when(tbScreeningRepo.save(any(TBScreening.class))).thenReturn(new TBScreening()); + String result = tbScreeningService.save(req); + assertTrue(result.contains("no of tb screening items saved: 1")); + } + + @Test + void save_existingTBScreening_success() throws Exception { + TBScreeningDTO dto = new TBScreeningDTO(); + dto.setBenId(2L); + TBScreeningRequestDTO req = new TBScreeningRequestDTO(); + req.setUserId(20); + req.setTbScreeningList(Collections.singletonList(dto)); + TBScreening existing = new TBScreening(); + existing.setId(99L); + when(tbScreeningRepo.getByUserIdAndBenId(2L, 20)).thenReturn(existing); + when(tbScreeningRepo.save(any(TBScreening.class))).thenReturn(existing); + String result = tbScreeningService.save(req); + assertTrue(result.contains("no of tb screening items saved: 1")); + } + + @Test + void save_exception() throws Exception { + TBScreeningDTO dto = new TBScreeningDTO(); + dto.setBenId(3L); + TBScreeningRequestDTO req = new TBScreeningRequestDTO(); + req.setUserId(30); + req.setTbScreeningList(Collections.singletonList(dto)); + when(tbScreeningRepo.getByUserIdAndBenId(3L, 30)).thenThrow(new RuntimeException("fail")); + assertThrows(Exception.class, () -> tbScreeningService.save(req)); + } + + @Test + void getByUserId_success() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + List tbList = Arrays.asList(new TBScreening(), new TBScreening()); + when(tbScreeningRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(tbList); + String json = tbScreeningService.getByUserId(req); + assertNotNull(json); + TBScreeningRequestDTO result = new Gson().fromJson(json, TBScreeningRequestDTO.class); + assertEquals(2, result.getTbScreeningList().size()); + assertEquals(ashaId, result.getUserId()); + } + + @Test + void getByUserId_emptyList() { + GetBenRequestHandler req = mock(GetBenRequestHandler.class); + Integer ashaId = 123; + Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); + when(req.getAshaId()).thenReturn(ashaId); + when(req.getFromDate()).thenReturn(fromDate); + when(req.getToDate()).thenReturn(toDate); + when(tbScreeningRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); + String json = tbScreeningService.getByUserId(req); + assertNotNull(json); + TBScreeningRequestDTO result = new Gson().fromJson(json, TBScreeningRequestDTO.class); + assertEquals(0, result.getTbScreeningList().size()); + assertEquals(ashaId, result.getUserId()); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/TBSuspectedServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/TBSuspectedServiceImplTest.java new file mode 100644 index 000000000..b6259516b --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/TBSuspectedServiceImplTest.java @@ -0,0 +1,91 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.TBSuspected; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.TBSuspectedDTO; +import com.iemr.flw.dto.iemr.TBSuspectedRequestDTO; +import com.iemr.flw.repo.iemr.TBSuspectedRepo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +class TBSuspectedServiceImplTest { + @Mock + private TBSuspectedRepo tbSuspectedRepo; + + @InjectMocks + private TBSuspectedServiceImpl service; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void getByBenId_alwaysReturnsNull() throws Exception { + assertNull(service.getByBenId(1L, "auth")); + } + + @Test + void save_newAndExistingSuspected() throws Exception { + TBSuspectedDTO dto1 = new TBSuspectedDTO(); + dto1.setBenId(1L); + TBSuspectedDTO dto2 = new TBSuspectedDTO(); + dto2.setBenId(2L); + TBSuspectedRequestDTO req = new TBSuspectedRequestDTO(); + req.setUserId(100); // Integer + req.setTbSuspectedList(Arrays.asList(dto1, dto2)); + + // First is new, second is existing + when(tbSuspectedRepo.getByUserIdAndBenId(1L, 100)).thenReturn(null); + TBSuspected existing = new TBSuspected(); + existing.setId(99L); + when(tbSuspectedRepo.getByUserIdAndBenId(2L, 100)).thenReturn(existing); + + String result = service.save(req); + assertTrue(result.contains("no of tb suspected items saved:2")); + verify(tbSuspectedRepo, times(2)).save(any(TBSuspected.class)); + } + + @Test + void getByUserId_returnsJsonWithCorrectUserIdAndList() { + GetBenRequestHandler req = new GetBenRequestHandler(); + req.setAshaId(123); // Integer + Timestamp from = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp to = Timestamp.valueOf("2023-12-31 00:00:00"); + req.setFromDate(from); + req.setToDate(to); + TBSuspected suspected = new TBSuspected(); + suspected.setId(1L); + when(tbSuspectedRepo.getByUserId(123, from, to)).thenReturn(Collections.singletonList(suspected)); + String json = service.getByUserId(req); + assertTrue(json.contains("\"userId\":123")); + assertTrue(json.contains("tbSuspectedList")); + } + + @Test + void getByUserId_emptyList() { + GetBenRequestHandler req = new GetBenRequestHandler(); + req.setAshaId(123); // Integer + Timestamp from = Timestamp.valueOf("2023-01-01 00:00:00"); + Timestamp to = Timestamp.valueOf("2023-12-31 00:00:00"); + req.setFromDate(from); + req.setToDate(to); + when(tbSuspectedRepo.getByUserId(anyInt(), any(Timestamp.class), any(Timestamp.class))).thenReturn(Collections.emptyList()); + String json = service.getByUserId(req); + assertTrue(json.contains("tbSuspectedList")); + } +} diff --git a/src/test/java/com/iemr/flw/service/impl/UserServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/UserServiceImplTest.java new file mode 100644 index 000000000..3bf8772d7 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/impl/UserServiceImplTest.java @@ -0,0 +1,41 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.dto.iemr.UserServiceRoleDTO; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import java.util.Collections; +import java.util.List; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class UserServiceImplTest { + @Mock + private UserServiceRoleRepo userServiceRoleRepo; + + @InjectMocks + private UserServiceImpl userService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void getUserDetail_returnsUserRole() { + UserServiceRoleDTO dto = new UserServiceRoleDTO(); + when(userServiceRoleRepo.getUserRole(123)).thenReturn(Collections.singletonList(dto)); + UserServiceRoleDTO result = userService.getUserDetail(123); + assertSame(dto, result); + verify(userServiceRoleRepo).getUserRole(123); + } + + @Test + void getUserDetail_emptyList_throwsException() { + when(userServiceRoleRepo.getUserRole(456)).thenReturn(Collections.emptyList()); + assertThrows(IndexOutOfBoundsException.class, () -> userService.getUserDetail(456)); + } +} From a5432da83fb4dd9656dea6a7d9c50f3d1bead096 Mon Sep 17 00:00:00 2001 From: Zapper9982 Date: Wed, 3 Sep 2025 00:11:15 +0530 Subject: [PATCH 003/237] test(workflow):workflow working --- .github/workflows/testcase-coverage.yml | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/testcase-coverage.yml diff --git a/.github/workflows/testcase-coverage.yml b/.github/workflows/testcase-coverage.yml new file mode 100644 index 000000000..45da70004 --- /dev/null +++ b/.github/workflows/testcase-coverage.yml @@ -0,0 +1,44 @@ +name: TestCase Coverage Check +on: + pull_request_target: + + +permissions: + contents: read + pull-requests: write + actions: read + +jobs: + Build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: Setup JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Build with Maven + run: mvn clean verify + + - name: Upload JaCoCo Report Artifact + uses: actions/upload-artifact@v4 + with: + name: jacoco-report + path: target/site/jacoco/jacoco.xml + if-no-files-found: warn + + - name: Compare JaCoCo Coverage + uses: madrapps/jacoco-report@v1.7.2 + with: + paths: ${{ github.workspace }}/target/site/jacoco/jacoco.xml + token: ${{ secrets.GITHUB_TOKEN }} + min-coverage-overall: 0 + title: Code Coverage Report + comment-type: pr_comment \ No newline at end of file From 4ec1f551985b057808248a8cd4db6aaa9ed0656e Mon Sep 17 00:00:00 2001 From: Zapper9982 Date: Thu, 4 Sep 2025 00:09:12 +0530 Subject: [PATCH 004/237] test(workflow):making changes so that PR comment posted on PR's not from fork --- .github/workflows/testcase-coverage.yml | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/testcase-coverage.yml b/.github/workflows/testcase-coverage.yml index 45da70004..5e71c85c6 100644 --- a/.github/workflows/testcase-coverage.yml +++ b/.github/workflows/testcase-coverage.yml @@ -1,22 +1,20 @@ name: TestCase Coverage Check -on: - pull_request_target: +on: + pull_request: + types: [opened, synchronize] -permissions: - contents: read - pull-requests: write - actions: read +permissions: {} jobs: - Build: + build_and_check_coverage: runs-on: ubuntu-latest + permissions: + contents: read + steps: - name: Checkout code uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: 0 - name: Setup JDK 17 uses: actions/setup-java@v4 @@ -24,21 +22,23 @@ jobs: java-version: '17' distribution: 'temurin' + - name: Cache Maven dependencies + uses: actions/cache@v3 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-m2- + - name: Build with Maven run: mvn clean verify - - name: Upload JaCoCo Report Artifact - uses: actions/upload-artifact@v4 - with: - name: jacoco-report - path: target/site/jacoco/jacoco.xml - if-no-files-found: warn - - - name: Compare JaCoCo Coverage + - name: Run Coverage Check uses: madrapps/jacoco-report@v1.7.2 with: - paths: ${{ github.workspace }}/target/site/jacoco/jacoco.xml + paths: target/site/jacoco/jacoco.xml token: ${{ secrets.GITHUB_TOKEN }} - min-coverage-overall: 0 + min-coverage-overall: 40 + min-coverage-changed-files: 60 title: Code Coverage Report comment-type: pr_comment \ No newline at end of file From 3fead247f1286236c45dcf4380eb9a85f4f26114 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 10 Dec 2025 16:09:55 +0530 Subject: [PATCH 005/237] add visit_date in getHbnc details api --- .../java/com/iemr/flw/service/impl/ChildCareServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index da4217269..9ca6e483d 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -223,6 +223,7 @@ public List getHBNCDetails(GetBenRequestHandler dto) { // Convert all fields to Map Map fields = new HashMap<>(); addIfValid(fields, "visit_day", visit.getVisit_day()); + addIfValid(fields, "visit_date", visit.getVisit_date()); addIfValid(fields, "due_date", visit.getDue_date()); addIfValid(fields, "is_baby_alive", convert(visit.getIs_baby_alive())); addIfValid(fields, "date_of_death", visit.getDate_of_death()); From fa716de0af0f0d5e0d734679365436954c5b9832 Mon Sep 17 00:00:00 2001 From: DurgaPrasad-54 Date: Mon, 19 Jan 2026 20:51:09 +0530 Subject: [PATCH 006/237] docs(readme): add documentation badge --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 560f69a7e..75a0708f0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # Frontline Health Workers (FLW) Mobile App API Module +[![DeepWiki](https://img.shields.io/badge/DeepWiki-PSMRI%2FFLW--API-blue)](https://deepwiki.com/PSMRI/FLW-API) + + ### Introduction Frontline Health Workers (FLW) Mobile App is known with brand name _SAKHI_ App. Currently this _SAKHI_ App is designed for Accredited Social Health Activist (ASHA). From 3d5022b7202288f1aafb9a0805469ed95c10c08b Mon Sep 17 00:00:00 2001 From: KOPPIREDDY DURGA PRASAD <144464542+DurgaPrasad-54@users.noreply.github.com> Date: Mon, 2 Mar 2026 10:10:30 +0530 Subject: [PATCH 007/237] feat(health,version): add health and version endpoints (#208) * feat(health,version): add health and version endpoints * fix(health): cancel in-flight futures on generic failure * fix: remove duplicate plugin and unused variable --- pom.xml | 26 + .../controller/health/HealthController.java | 83 +++ .../controller/version/VersionController.java | 80 +++ .../flw/service/health/HealthService.java | 517 ++++++++++++++++++ .../flw/utils/JwtUserIdValidationFilter.java | 4 +- 5 files changed, 709 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/iemr/flw/controller/health/HealthController.java create mode 100644 src/main/java/com/iemr/flw/controller/version/VersionController.java create mode 100644 src/main/java/com/iemr/flw/service/health/HealthService.java diff --git a/pom.xml b/pom.xml index f3433e094..f9f4e231f 100644 --- a/pom.xml +++ b/pom.xml @@ -340,6 +340,32 @@ + + io.github.git-commit-id + git-commit-id-maven-plugin + 9.0.2 + + + get-the-git-infos + + revision + + initialize + + + + true + ${project.build.outputDirectory}/git.properties + + ^git.branch$ + ^git.commit.id.abbrev$ + ^git.build.version$ + ^git.build.time$ + + false + false + + org.apache.maven.plugins maven-antrun-plugin diff --git a/src/main/java/com/iemr/flw/controller/health/HealthController.java b/src/main/java/com/iemr/flw/controller/health/HealthController.java new file mode 100644 index 000000000..933085544 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/health/HealthController.java @@ -0,0 +1,83 @@ +/* +* 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.controller.health; + +import java.time.Instant; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.iemr.flw.service.health.HealthService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +@RestController +@RequestMapping("/health") +@Tag(name = "Health Check", description = "APIs for checking infrastructure health status") +public class HealthController { + + private static final Logger logger = LoggerFactory.getLogger(HealthController.class); + + private final HealthService healthService; + + public HealthController(HealthService healthService) { + this.healthService = healthService; + } + + @GetMapping + @Operation(summary = "Check infrastructure health", + description = "Returns the health status of MySQL, Redis, and other configured services") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "Services are UP or DEGRADED (operational with warnings)"), + @ApiResponse(responseCode = "503", description = "One or more critical services are DOWN") + }) + public ResponseEntity> checkHealth() { + logger.debug("Health check endpoint called"); + + try { + Map healthStatus = healthService.checkHealth(); + String overallStatus = (String) healthStatus.get("status"); + + HttpStatus httpStatus = "DOWN".equals(overallStatus) ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.OK; + + logger.debug("Health check completed with status: {}", overallStatus); + return new ResponseEntity<>(healthStatus, httpStatus); + + } catch (Exception e) { + logger.error("Unexpected error during health check", e); + + Map errorResponse = Map.of( + "status", "DOWN", + "timestamp", Instant.now().toString() + ); + + return new ResponseEntity<>(errorResponse, HttpStatus.SERVICE_UNAVAILABLE); + } + } +} diff --git a/src/main/java/com/iemr/flw/controller/version/VersionController.java b/src/main/java/com/iemr/flw/controller/version/VersionController.java new file mode 100644 index 000000000..f2f2bf66f --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/version/VersionController.java @@ -0,0 +1,80 @@ +/* +* 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.controller.version; + +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; + +@RestController +public class VersionController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + + private static final String UNKNOWN_VALUE = "unknown"; + + @Operation(summary = "Get version information") + @GetMapping(value = "/version", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> versionInformation() { + Map response = new LinkedHashMap<>(); + try { + logger.info("version Controller Start"); + Properties gitProperties = loadGitProperties(); + response.put("buildTimestamp", gitProperties.getProperty("git.build.time", UNKNOWN_VALUE)); + response.put("version", gitProperties.getProperty("git.build.version", UNKNOWN_VALUE)); + response.put("branch", gitProperties.getProperty("git.branch", UNKNOWN_VALUE)); + response.put("commitHash", gitProperties.getProperty("git.commit.id.abbrev", UNKNOWN_VALUE)); + } catch (Exception e) { + logger.error("Failed to load version information", e); + response.put("buildTimestamp", UNKNOWN_VALUE); + response.put("version", UNKNOWN_VALUE); + response.put("branch", UNKNOWN_VALUE); + response.put("commitHash", UNKNOWN_VALUE); + } + logger.info("version Controller End"); + return ResponseEntity.ok(response); + } + + private Properties loadGitProperties() throws IOException { + Properties properties = new Properties(); + try (InputStream input = getClass().getClassLoader() + .getResourceAsStream("git.properties")) { + if (input != null) { + properties.load(input); + } + } + return properties; + } +} diff --git a/src/main/java/com/iemr/flw/service/health/HealthService.java b/src/main/java/com/iemr/flw/service/health/HealthService.java new file mode 100644 index 000000000..084ffe5e4 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/health/HealthService.java @@ -0,0 +1,517 @@ +/* +* 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.service.health; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.time.Instant; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; +import jakarta.annotation.PreDestroy; +import javax.sql.DataSource; +import com.zaxxer.hikari.HikariDataSource; +import com.zaxxer.hikari.HikariPoolMXBean; +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +@Service +public class HealthService { + + private static final Logger logger = LoggerFactory.getLogger(HealthService.class); + + private static final String STATUS_KEY = "status"; + private static final String STATUS_UP = "UP"; + private static final String STATUS_DOWN = "DOWN"; + private static final String STATUS_DEGRADED = "DEGRADED"; + private static final String SEVERITY_KEY = "severity"; + private static final String SEVERITY_OK = "OK"; + private static final String SEVERITY_WARNING = "WARNING"; + private static final String SEVERITY_CRITICAL = "CRITICAL"; + private static final String ERROR_KEY = "error"; + private static final String MESSAGE_KEY = "message"; + private static final String RESPONSE_TIME_KEY = "responseTimeMs"; + private static final long MYSQL_TIMEOUT_SECONDS = 3; + private static final long REDIS_TIMEOUT_SECONDS = 3; + + private static final long ADVANCED_CHECKS_THROTTLE_SECONDS = 30; + private static final long RESPONSE_TIME_THRESHOLD_MS = 2000; + + private static final String DIAGNOSTIC_LOCK_WAIT = "MYSQL_LOCK_WAIT"; + private static final String DIAGNOSTIC_SLOW_QUERIES = "MYSQL_SLOW_QUERIES"; + private static final String DIAGNOSTIC_POOL_EXHAUSTED = "MYSQL_POOL_EXHAUSTED"; + private static final String DIAGNOSTIC_LOG_TEMPLATE = "Diagnostic: {}"; + + private final DataSource dataSource; + private final RedisTemplate redisTemplate; + private final ExecutorService executorService; + + private volatile long lastAdvancedCheckTime = 0; + private volatile AdvancedCheckResult cachedAdvancedCheckResult = null; + private final ReentrantReadWriteLock advancedCheckLock = new ReentrantReadWriteLock(); + private final AtomicBoolean advancedCheckInProgress = new AtomicBoolean(false); + + private static final boolean ADVANCED_HEALTH_CHECKS_ENABLED = true; + + public HealthService(DataSource dataSource, + @Autowired(required = false) RedisTemplate redisTemplate) { + this.dataSource = dataSource; + this.redisTemplate = redisTemplate; + this.executorService = Executors.newFixedThreadPool(6); + } + + @PreDestroy + public void shutdown() { + if (executorService != null && !executorService.isShutdown()) { + try { + executorService.shutdown(); + if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) { + executorService.shutdownNow(); + logger.warn("ExecutorService did not terminate gracefully"); + } + } catch (InterruptedException e) { + executorService.shutdownNow(); + Thread.currentThread().interrupt(); + logger.warn("ExecutorService shutdown interrupted", e); + } + } + } + + public Map checkHealth() { + Map response = new LinkedHashMap<>(); + response.put("timestamp", Instant.now().toString()); + + Map mysqlStatus = new ConcurrentHashMap<>(); + Map redisStatus = new ConcurrentHashMap<>(); + + if (!executorService.isShutdown()) { + performHealthChecks(mysqlStatus, redisStatus); + } + + ensurePopulated(mysqlStatus, "MySQL"); + ensurePopulated(redisStatus, "Redis"); + + Map> components = new LinkedHashMap<>(); + components.put("mysql", mysqlStatus); + components.put("redis", redisStatus); + + response.put("components", components); + response.put(STATUS_KEY, computeOverallStatus(components)); + + return response; + } + + private void performHealthChecks(Map mysqlStatus, Map redisStatus) { + Future mysqlFuture = null; + Future redisFuture = null; + try { + mysqlFuture = executorService.submit( + () -> performHealthCheck("MySQL", mysqlStatus, this::checkMySQLHealthSync)); + redisFuture = executorService.submit( + () -> performHealthCheck("Redis", redisStatus, this::checkRedisHealthSync)); + + awaitHealthChecks(mysqlFuture, redisFuture); + } catch (TimeoutException e) { + logger.warn("Health check aggregate timeout after {} seconds", getMaxTimeout()); + cancelFutures(mysqlFuture, redisFuture); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.warn("Health check was interrupted"); + cancelFutures(mysqlFuture, redisFuture); + } catch (Exception e) { + logger.warn("Health check execution error: {}", e.getMessage()); + cancelFutures(mysqlFuture, redisFuture); + } + } + + private void awaitHealthChecks(Future mysqlFuture, Future redisFuture) throws TimeoutException, InterruptedException, ExecutionException { + long maxTimeout = getMaxTimeout(); + long deadlineNs = System.nanoTime() + TimeUnit.SECONDS.toNanos(maxTimeout); + + mysqlFuture.get(maxTimeout, TimeUnit.SECONDS); + long remainingNs = deadlineNs - System.nanoTime(); + + if (remainingNs > 0) { + redisFuture.get(remainingNs, TimeUnit.NANOSECONDS); + } else { + redisFuture.cancel(true); + } + } + + private long getMaxTimeout() { + return Math.max(MYSQL_TIMEOUT_SECONDS, REDIS_TIMEOUT_SECONDS) + 1; + } + + private void cancelFutures(Future mysqlFuture, Future redisFuture) { + if (mysqlFuture != null) mysqlFuture.cancel(true); + if (redisFuture != null) redisFuture.cancel(true); + } + + private void ensurePopulated(Map status, String componentName) { + if (!status.containsKey(STATUS_KEY)) { + status.put(STATUS_KEY, STATUS_DOWN); + status.put(SEVERITY_KEY, SEVERITY_CRITICAL); + status.put(ERROR_KEY, componentName + " health check did not complete in time"); + } + } + + private HealthCheckResult checkMySQLHealthSync() { + try (Connection connection = dataSource.getConnection(); + PreparedStatement stmt = connection.prepareStatement("SELECT 1 as health_check")) { + + stmt.setQueryTimeout((int) MYSQL_TIMEOUT_SECONDS); + + try (ResultSet rs = stmt.executeQuery()) { + if (!rs.next()) { + return new HealthCheckResult(false, "No result from health check query", false); + } + } + } catch (Exception e) { + logger.warn("MySQL health check failed: {}", e.getMessage(), e); + return new HealthCheckResult(false, "MySQL connection failed", false); + } + boolean isDegraded = performAdvancedMySQLChecksWithThrottle(); + return new HealthCheckResult(true, null, isDegraded); + } + + private HealthCheckResult checkRedisHealthSync() { + if (redisTemplate == null) { + return new HealthCheckResult(true, "Redis not configured — skipped", false); + } + + try { + String pong = redisTemplate.execute((org.springframework.data.redis.core.RedisCallback) (connection) -> connection.ping()); + + if ("PONG".equals(pong)) { + return new HealthCheckResult(true, null, false); + } + + return new HealthCheckResult(false, "Redis PING failed", false); + + } catch (Exception e) { + logger.warn("Redis health check failed: {}", e.getMessage(), e); + return new HealthCheckResult(false, "Redis connection failed", false); + } + } + + private Map performHealthCheck(String componentName, + Map status, + Supplier checker) { + long startTime = System.currentTimeMillis(); + + try { + HealthCheckResult result = checker.get(); + long responseTime = System.currentTimeMillis() - startTime; + + String componentStatus; + if (!result.isHealthy) { + componentStatus = STATUS_DOWN; + } else if (result.isDegraded) { + componentStatus = STATUS_DEGRADED; + } else { + componentStatus = STATUS_UP; + } + status.put(STATUS_KEY, componentStatus); + + status.put(RESPONSE_TIME_KEY, responseTime); + + String severity = determineSeverity(result.isHealthy, responseTime, result.isDegraded); + status.put(SEVERITY_KEY, severity); + + if (result.error != null) { + String fieldKey = result.isHealthy ? MESSAGE_KEY : ERROR_KEY; + status.put(fieldKey, result.error); + } + + return status; + + } catch (Exception e) { + long responseTime = System.currentTimeMillis() - startTime; + logger.error("{} health check failed with exception: {}", componentName, e.getMessage(), e); + + status.put(STATUS_KEY, STATUS_DOWN); + status.put(RESPONSE_TIME_KEY, responseTime); + status.put(SEVERITY_KEY, SEVERITY_CRITICAL); + status.put(ERROR_KEY, "Health check failed with an unexpected error"); + + return status; + } + } + + private String determineSeverity(boolean isHealthy, long responseTimeMs, boolean isDegraded) { + if (!isHealthy) { + return SEVERITY_CRITICAL; + } + + if (isDegraded) { + return SEVERITY_WARNING; + } + + if (responseTimeMs > RESPONSE_TIME_THRESHOLD_MS) { + return SEVERITY_WARNING; + } + + return SEVERITY_OK; + } + + private String computeOverallStatus(Map> components) { + boolean hasCritical = false; + boolean hasDegraded = false; + + for (Map componentStatus : components.values()) { + String status = (String) componentStatus.get(STATUS_KEY); + String severity = (String) componentStatus.get(SEVERITY_KEY); + + if (STATUS_DOWN.equals(status) || SEVERITY_CRITICAL.equals(severity)) { + hasCritical = true; + } + + if (STATUS_DEGRADED.equals(status)) { + hasDegraded = true; + } + + if (SEVERITY_WARNING.equals(severity)) { + hasDegraded = true; + } + } + + if (hasCritical) { + return STATUS_DOWN; + } + + if (hasDegraded) { + return STATUS_DEGRADED; + } + + return STATUS_UP; + } + + private boolean performAdvancedMySQLChecksWithThrottle() { + if (!ADVANCED_HEALTH_CHECKS_ENABLED) { + return false; + } + + long currentTime = System.currentTimeMillis(); + + advancedCheckLock.readLock().lock(); + try { + if (cachedAdvancedCheckResult != null && + (currentTime - lastAdvancedCheckTime) < ADVANCED_CHECKS_THROTTLE_SECONDS * 1000) { + return cachedAdvancedCheckResult.isDegraded; + } + } finally { + advancedCheckLock.readLock().unlock(); + } + + // Only one thread may submit; others fall back to the (stale) cache + if (!advancedCheckInProgress.compareAndSet(false, true)) { + advancedCheckLock.readLock().lock(); + try { + return cachedAdvancedCheckResult != null && cachedAdvancedCheckResult.isDegraded; + } finally { + advancedCheckLock.readLock().unlock(); + } + } + + try { + // Perform DB I/O outside the write lock to avoid lock contention + AdvancedCheckResult result; + try (Connection connection = dataSource.getConnection()) { + result = performAdvancedMySQLChecks(connection); + } catch (Exception e) { + if (e.getCause() instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + logger.debug("Failed to get connection for advanced checks: {}", e.getMessage()); + result = new AdvancedCheckResult(false); + } + + // Re-acquire write lock only to update the cache atomically + advancedCheckLock.writeLock().lock(); + try { + lastAdvancedCheckTime = currentTime; + cachedAdvancedCheckResult = result; + return result.isDegraded; + } finally { + advancedCheckLock.writeLock().unlock(); + } + } finally { + advancedCheckInProgress.set(false); + } + } + + private AdvancedCheckResult performAdvancedMySQLChecks(Connection connection) { + try { + boolean hasIssues = false; + + if (hasLockWaits(connection)) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_LOCK_WAIT); + hasIssues = true; + } + + if (hasSlowQueries(connection)) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_SLOW_QUERIES); + hasIssues = true; + } + + if (hasConnectionPoolExhaustion()) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_POOL_EXHAUSTED); + hasIssues = true; + } + + return new AdvancedCheckResult(hasIssues); + } catch (Exception e) { + logger.debug("Advanced MySQL checks encountered exception, marking degraded"); + return new AdvancedCheckResult(true); + } + } + + private boolean hasLockWaits(Connection connection) { + try (PreparedStatement stmt = connection.prepareStatement( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST " + + "WHERE (state = 'Waiting for table metadata lock' " + + " OR state = 'Waiting for row lock' " + + " OR state = 'Waiting for lock') " + + "AND user = SUBSTRING_INDEX(USER(), '@', 1)")) { + stmt.setQueryTimeout(2); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + int lockCount = rs.getInt(1); + return lockCount > 0; + } + } + } catch (Exception e) { + logger.debug("Could not check for lock waits"); + } + return false; + } + + + private boolean hasSlowQueries(Connection connection) { + try (PreparedStatement stmt = connection.prepareStatement( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST " + + "WHERE command != 'Sleep' AND time > ? AND user = SUBSTRING_INDEX(USER(), '@', 1)")) { + stmt.setQueryTimeout(2); + stmt.setInt(1, 10); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + int slowQueryCount = rs.getInt(1); + return slowQueryCount > 3; + } + } + } catch (Exception e) { + logger.debug("Could not check for slow queries"); + } + return false; + } + + private boolean hasConnectionPoolExhaustion() { + if (dataSource instanceof HikariDataSource hikariDataSource) { + try { + HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean(); + + if (poolMXBean != null) { + int activeConnections = poolMXBean.getActiveConnections(); + int maxPoolSize = hikariDataSource.getMaximumPoolSize(); + + int threshold = (int) (maxPoolSize * 0.8); + return activeConnections > threshold; + } + } catch (Exception e) { + logger.debug("Could not retrieve HikariCP pool metrics"); + } + } + + return checkPoolMetricsViaJMX(); + } + + private boolean checkPoolMetricsViaJMX() { + try { + MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + ObjectName objectName = new ObjectName("com.zaxxer.hikari:type=Pool (*)"); + var mBeans = mBeanServer.queryMBeans(objectName, null); + + for (var mBean : mBeans) { + if (evaluatePoolMetrics(mBeanServer, mBean.getObjectName())) { + return true; + } + } + } catch (Exception e) { + logger.debug("Could not access HikariCP pool metrics via JMX"); + } + + logger.debug("Pool exhaustion check disabled: HikariCP metrics unavailable"); + return false; + } + + private boolean evaluatePoolMetrics(MBeanServer mBeanServer, ObjectName objectName) { + try { + Integer activeConnections = (Integer) mBeanServer.getAttribute(objectName, "ActiveConnections"); + Integer maximumPoolSize = (Integer) mBeanServer.getAttribute(objectName, "MaximumPoolSize"); + + if (activeConnections != null && maximumPoolSize != null) { + int threshold = (int) (maximumPoolSize * 0.8); + return activeConnections > threshold; + } + } catch (Exception e) { + // Continue to next MBean + } + return false; + } + + private static class AdvancedCheckResult { + final boolean isDegraded; + + AdvancedCheckResult(boolean isDegraded) { + this.isDegraded = isDegraded; + } + } + + private static class HealthCheckResult { + final boolean isHealthy; + final String error; + final boolean isDegraded; + + HealthCheckResult(boolean isHealthy, String error, boolean isDegraded) { + this.isHealthy = isHealthy; + this.error = error; + this.isDegraded = isDegraded; + } + } +} diff --git a/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java index 7cc17200a..8dbc55725 100644 --- a/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java @@ -152,7 +152,9 @@ private boolean shouldSkipPath(String path, String contextPath) { return path.equals(contextPath + "/user/userAuthenticate") || path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession") || path.startsWith(contextPath + "/swagger-ui") || path.startsWith(contextPath + "/v3/api-docs") - || path.startsWith(contextPath + "/public"); + || path.startsWith(contextPath + "/public") + || path.equals(contextPath + "/health") + || path.equals(contextPath + "/version"); } private String getJwtTokenFromCookies(HttpServletRequest request) { From 690dbee074e86be0985cd2c2d63177c9ef102255 Mon Sep 17 00:00:00 2001 From: KOPPIREDDY DURGA PRASAD <144464542+DurgaPrasad-54@users.noreply.github.com> Date: Mon, 2 Mar 2026 10:11:38 +0530 Subject: [PATCH 008/237] chore(swagger): add swagger automation github workflow (#207) * chore(swagger): add swagger automation github workflow * fix(swagger): harden CI shutdown, isolate H2 to swagger profile, disable redis sessions, and set API version --- .github/workflows/swagger-json.yml | 106 ++++++++++++++++++ pom.xml | 11 ++ .../com/iemr/flw/config/SwaggerConfig.java | 28 +++-- .../resources/application-swagger.properties | 79 +++++++++++++ 4 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/swagger-json.yml create mode 100644 src/main/resources/application-swagger.properties diff --git a/.github/workflows/swagger-json.yml b/.github/workflows/swagger-json.yml new file mode 100644 index 000000000..2c2fb910a --- /dev/null +++ b/.github/workflows/swagger-json.yml @@ -0,0 +1,106 @@ +name: Sync Swagger to AMRIT-Docs + +on: + push: + branches: [ main ] + workflow_dispatch: + +jobs: + swagger-sync: + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Checkout API repo + uses: actions/checkout@v4 + + - name: Set up Java 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + cache: maven + + - name: Build API (skip tests) + run: mvn -B clean package -DskipTests -DENV_VAR=local -Pswagger + + - name: Install jq + run: sudo apt-get update && sudo apt-get install -y jq + + - name: Run API in swagger profile + run: | + nohup java -jar target/flw-api-*.war \ + --spring.profiles.active=swagger \ + --server.port=9090 \ + > app.log 2>&1 & + echo $! > api_pid.txt + + - name: Wait for API & fetch Swagger + run: | + for i in {1..40}; do + CODE=$(curl --connect-timeout 2 --max-time 5 -s -o swagger_raw.json -w "%{http_code}" http://localhost:9090/v3/api-docs || true) + + if [ "$CODE" = "200" ]; then + jq . swagger_raw.json > flw-api.json || { + echo "Swagger JSON invalid" + cat swagger_raw.json + exit 1 + } + + if [ "$(jq '.paths | length' flw-api.json)" -eq 0 ]; then + echo "Swagger paths empty – failing" + exit 1 + fi + + echo "Swagger generated successfully" + exit 0 + fi + + echo "Waiting for API... ($i)" + sleep 4 + done + + echo "Swagger not generated" + cat app.log || true + exit 1 + + - name: Stop API + if: always() + run: | + # Kill the process directly by PID (process-group kill is unreliable in CI) + sleep 5 + if [ -f api_pid.txt ]; then + PID=$(cat api_pid.txt) + kill -TERM "$PID" 2>/dev/null || true + sleep 2 + kill -9 "$PID" 2>/dev/null || true + fi + # Fallback: kill any remaining java process on port 9090 + fuser -k 9090/tcp 2>/dev/null || true + + - name: Checkout AMRIT-Docs + uses: actions/checkout@v4 + with: + repository: PSMRI/AMRIT-Docs + token: ${{ secrets.DOCS_REPO_TOKEN }} + path: amrit-docs + fetch-depth: 0 + + - name: Copy Swagger JSON + run: | + mkdir -p amrit-docs/docs/swagger + cp flw-api.json amrit-docs/docs/swagger/flw-api.json + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v8 + with: + token: ${{ secrets.DOCS_REPO_TOKEN }} + path: amrit-docs + branch: auto/swagger-update-flw-api + base: main + commit-message: "chore(docs): auto-update FLW-API swagger" + title: "chore(docs): auto-update FLW-API swagger" + delete-branch: true + body: | + This PR automatically updates FLW-API Swagger JSON + from the latest main branch build. diff --git a/pom.xml b/pom.xml index f9f4e231f..9a2faeafe 100644 --- a/pom.xml +++ b/pom.xml @@ -250,6 +250,17 @@ + + swagger + + + + com.h2database + h2 + runtime + + + 1097_flw diff --git a/src/main/java/com/iemr/flw/config/SwaggerConfig.java b/src/main/java/com/iemr/flw/config/SwaggerConfig.java index 1052c2af7..f551de7c5 100644 --- a/src/main/java/com/iemr/flw/config/SwaggerConfig.java +++ b/src/main/java/com/iemr/flw/config/SwaggerConfig.java @@ -23,21 +23,35 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import java.util.List; @Configuration public class SwaggerConfig { + private static final String DEFAULT_SERVER_URL = "http://localhost:9090"; + private static final String BEARER_AUTH_SCHEME = "bearerAuth"; + @Bean - OpenAPI customOpenAPI() { - return new OpenAPI().info(new - Info().title("FLW API").version("version").description("A microservice for the creation and management of beneficiaries.")) - .addSecurityItem(new SecurityRequirement().addList("my security")) - .components(new Components().addSecuritySchemes("my security", - new SecurityScheme().name("my security").type(SecurityScheme.Type.HTTP).scheme("bearer"))); - } + public OpenAPI customOpenAPI(Environment env) { + String devUrl = env.getProperty("api.dev.url", DEFAULT_SERVER_URL); + String uatUrl = env.getProperty("api.uat.url", DEFAULT_SERVER_URL); + String demoUrl = env.getProperty("api.demo.url", DEFAULT_SERVER_URL); + return new OpenAPI() + .info(new Info().title("FLW API").version("3.1.0").description("A microservice for the creation and management of Field Level Workers (FLW) in the AMRIT ecosystem.")) + .addSecurityItem(new SecurityRequirement().addList(BEARER_AUTH_SCHEME)) + .components(new Components().addSecuritySchemes(BEARER_AUTH_SCHEME, + new SecurityScheme().name(BEARER_AUTH_SCHEME).type(SecurityScheme.Type.HTTP).scheme("bearer"))) + .servers(List.of( + new Server().url(devUrl).description("Dev"), + new Server().url(uatUrl).description("UAT"), + new Server().url(demoUrl).description("Demo") + )); + } } diff --git a/src/main/resources/application-swagger.properties b/src/main/resources/application-swagger.properties new file mode 100644 index 000000000..d8fdf13dd --- /dev/null +++ b/src/main/resources/application-swagger.properties @@ -0,0 +1,79 @@ +# Swagger server URLs +api.dev.url=${API_DEV_URL:https://amritwprdev.piramalswasthya.org} +api.uat.url=${API_UAT_URL:https://uatamrit.piramalswasthya.org} +api.demo.url=${API_DEMO_URL:https://amritdemo.piramalswasthya.org} + +# --- Swagger Profile Configuration --- +# Disable H2 console to avoid dataSource bean creation issues +spring.h2.console.enabled=false + +# Primary Database (using H2 for swagger generation) +spring.datasource.url=jdbc:h2:mem:swaggerdb +spring.datasource.username=SA +spring.datasource.password= +spring.datasource.driver-class-name=org.h2.Driver +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.jpa.hibernate.ddl-auto=none +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=false + +# Secondary Database (using H2 for swagger generation) +secondary.datasource.url=jdbc:h2:mem:swaggerdb2 +secondary.datasource.username=SA +secondary.datasource.password= +secondary.datasource.driver-class-name=org.h2.Driver + +# Redis Configuration (dummy for swagger) +spring.redis.host=localhost +spring.redis.port=6379 +spring.redis.password= + +# Basic configuration +server.port=8080 +logging.level.root=INFO +logging.level.org.springframework=INFO +management.endpoints.web.exposure.include=health,info +management.server.address=127.0.0.1 +management.server.port=8081 + +# JWT Configuration +jwt.secret=sample-jwt-secret + +# CORS Configuration +cors.allowed-origins=http://localhost:8080,http://localhost:9000 + +# External API placeholders (dummy values for swagger generation) +fhir-url=http://localhost:8093/ +tm-url=http://localhost:8089/ + +# Naming strategies +spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl +spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + +# Jackson configuration +spring.jackson.serialization.fail-on-empty-beans=false +spring.jackson.default-property-inclusion=NON_NULL +spring.jackson.deserialization.fail-on-unknown-properties=false + +# Session configuration (none for swagger profile - Redis not available in CI) +spring.session.store-type=none +iemr.extend.expiry.time=true +iemr.session.expiry.time=7200 +enableIPValidation=false + +# Logging +logging.path=logs/ +logging.file.name=logs/flw-api.log + +# SpringDoc configuration for OpenAPI/Swagger +springdoc.api-docs.path=/v3/api-docs +springdoc.swagger-ui.path=/swagger-ui.html +springdoc.swagger-ui.enabled=true +springdoc.api-docs.enabled=true +springdoc.swagger-ui.display-request-duration=true +springdoc.show-actuator=false + +# Additional CommonAPI placeholders +door-to-door-page-size=10 +get-HRP-Status=ANC/getHRPStatus +getHealthID=healthID/getBenhealthID From ed30f66c189a532a3e0bb53ce725d4201e16e30a Mon Sep 17 00:00:00 2001 From: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Date: Tue, 14 Jul 2026 18:16:59 +0530 Subject: [PATCH 009/237] Merge 3.8.2 to 3.10.0 (#282) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix DiseaseControl userId issue * fix DiseaseControl userId issue * fix DiseaseControl userId issue * fix eye checkup get list issue * fix ncd followup incentive issue * fix ncd followup incentive issue * fix ncd followup incentive issue * fix follow up date issue * fix follow up date issue * fix merge issue * fix merge issue * remove is_default_activity * remove is_default_activity * fix index of bound exception * fix approval status issue * fix approval status issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix count issue * fix eye checkup request issue * fix eye checkup request issue * fix eye checkup request issue * fix eye side issue * fix monthly incentive check issue * fix monthly incentive check issue * fix monthly incentive check issue * fix monthly incentive check issue * fix incentive issue * fix incentive issue * fix asha claimed incentive query * fix asha claimed incentive query * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix calculation of incentive * fix duplicate incentive for mdsr * fix duplicate incentive for mdsr * fix duplicate incentive for mdsr * fix duplicate incentive for mdsr * fix supervisor name * Client ID and Client Secret Disclosure (#239) * fix: client id and client secert key handle in backend * fix: client id and client secert key handle in backend * fix: remove hardcoded ABHA credentials and prevent local properties from being committed - Remove common_local.properties from git tracking (had hardcoded SBX_001542 client id/secret) - Add common_local.properties to .gitignore to prevent future commits - Add ABHA token config sample entries to common_example.properties Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 * feat: add facilityData to getUserDetail response based on user role (#240) Add FacilityDataService to build facilityData block (location, facilities, ashaList, totalAshaCount) based on userId and roleName — same logic as login response. ASHA Supervisor gets mapped ashaList, ASHA gets facility + supervisor + peers, CHO/ANM get facilities + ashaList at same facility. Co-authored-by: Claude Sonnet 4.6 * fix(security): replace extractUsername(token) with DB lookup across FLW-API (#241) All usages of jwtUtil.extractUsername (which reads PII from JWT sub claim) replaced with userRepo.getUserNamedByUserId(jwtUtil.extractUserId(token)). Username is now fetched from DB using userId — token PII not used anywhere in FLW-API. Affects BeneficiaryService, MaternalHealth, DiseaseControl, Campaign, IRSRound, SupervisorDashboard. Co-authored-by: Claude Sonnet 4.6 * feat: add mobile and employeeId to peersAtFacility, ashaList and supervisor in facilityData (#242) Co-authored-by: Claude Sonnet 4.6 * incentive chnages for release 3.8.2 * incentive chnages for release 3.8.2 * incentive chnages for release 3.8.2 * incentive chnages for release 3.8.2 * fix incentive issue for production (#243) * fix incentive issue for production * fix incentive issue for production * fix incentive issue for production * fix incentive issue for production * fix incentive issue on cg * fix incentive issue on cg * fix incentive issue on cg * fix incentive issue on cg * fix incentive issue on cg * fix incentive issue on cg * fix incentive * fix incentive * fix incentive * fix incentive * fix incentive * fix incentive issue and api response issue * fix incentive issue and api response issue * add unclaimed incentive count on dashboard * fix incentive issue in 3.8.2 * fix incentive issue in 3.8.2 * fix incentive issue in 3.8.2 * fix TB suspected incentive * Fix incentive for ANC * Fix incentive for ANC * Fix incentive for ANC * Fix incentive for ANC * fix ifa incentive * fix For motivating Female sterilization * fix For motivating Female sterilization * fix incentive for NCD follow up * fix pnc related incentive * fix pnc related incentive * fix IFA incentive logic issue * fix IFA incentive logic issue * fix IFA incentive logic issue * fix IFA incentive logic issue * fix IFA incentive logic issue * fixed malaria followup incentive * fixed malaria followup incentive * fixed malaria followup incentive * get ben details using abha ID * get ben details using abha ID * fix isDeactivate issue * Fix: Handled isDeactivate null values for old data records by defaulting to false. * Fix: Handled isDeactivate null values for old data records by defaulting to false. (#246) * fix motivating couples to maintain at least a two-year gap after marriage before first child * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * fix hbnc related incentive issue * fix hbnc related incentive issue * fix hbnc related incentive issue * fix hbnc related incentive issue * fix hbnc related incentive issue * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * fix incentive for Is Paiucd * add abha govt username and password * add abha govt username and password * add abha govt username and password * fix query issue in userService role * fix query issue in userService role * fix query issue in userService role * fix query issue in userService role * fix query issue in userService role * Fix/query issue in userservicerole (#249) * Fix: Handled isDeactivate null values for old data records by defaulting to false. * fix query issue in userService role * handel duplicate ben record * Fix/status code in ors ifa (#251) * Fix: Handled isDeactivate null values for old data records by defaulting to false. * change status code * change status code * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * fix sync issue * fix sync issue * fix sync issue * feature of abha check in our system * feature of abha check in our system * hbyc issue fixed * hbyc issue fixed * hbyc issue fixed * hbyc issue fixed * hbyc issue fixed * hbyc issue fixed * fix internal server error on abha id * fix internal server error on abha id * fix internal server error on abha id * fix internal server error on abha id * fix internal server error on abha id * fix internal server error on abha id * fix sam get api issue * fix date of referral issue * fix date of referral issue * fix date of referral issue * fix date of referral issue * fix hwc referral incentive issue * fix hwc referral incentive issue * fix hwc referral incentive issue * fix hwc referral incentive issue * fix hwc referral incentive issue * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix hbnc incentive * fix hbnc incentive * fix hbnc incentive * Fix/asha profile image issue (#265) * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix pnc incentive * fix pnc incentive * fix pnc incentive * fix vhnd incentive incentive * fix vhnd incentive incentive * fix vhnd incentive error * fix vhnd incentive error * fix vhnd incentive error * fix vhnd incentive error * fix cluster meeting incentive error * fix cluster meeting incentive error * fix tb incentive * fix slide test incentive * Fix/pb mb incentive issue 3.8.2 (#271) * fix duplicate incentive issue * fix duplicate incentive issue * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix hbyc incentive logic * fix hbyc incentive logic * fix hbyc incentive logic * optmiz query for incentive logic for hbnc * optmiz query for incentive logic for hbnc --------- Co-authored-by: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 --- .gitignore | 1 + pom.xml | 30 +- src/main/environment/common_ci.properties | 18 +- src/main/environment/common_docker.properties | 24 +- .../environment/common_example.properties | 6 + src/main/environment/common_local.properties | 45 - .../controller/AbhaBeneficiaryController.java | 54 ++ .../flw/controller/AbhaTokenController.java | 40 + .../flw/controller/AshaProfileController.java | 34 +- .../AshaSupervisorIncentiveApproval.java | 123 +++ .../flw/controller/BeneficiaryController.java | 99 +- .../flw/controller/CampaignController.java | 360 +++++++ .../flw/controller/ChildCareController.java | 146 +-- .../controller/DeathReportsController.java | 8 +- .../controller/DiseaseControlController.java | 108 ++- .../flw/controller/GeneralOPDController.java | 2 +- .../flw/controller/IRSRoundController.java | 18 +- .../flw/controller/IncentiveController.java | 135 ++- .../flw/controller/MaaMeetingController.java | 94 +- .../controller/MalariaFollowUpController.java | 52 +- .../controller/MaternalHealthController.java | 90 +- .../com/iemr/flw/controller/TBController.java | 85 +- .../flw/controller/UwinSessionController.java | 4 +- .../VillageLevelFormController.java | 14 +- .../controller/health/HealthController.java | 83 ++ .../controller/version/VersionController.java | 80 ++ .../RMNCHBeneficiaryDetailsRmnch.java | 3 + .../identity/RMNCHHouseHoldDetails.java | 4 + .../identity/RMNCHMBeneficiarydetail.java | 4 + .../com/iemr/flw/domain/iemr/ANCVisit.java | 6 + .../iemr/flw/domain/iemr/AbhaApiResponse.java | 21 + .../flw/domain/iemr/AncCounsellingCare.java | 128 +++ .../domain/iemr/AshaSupervisorMapping.java | 34 + .../com/iemr/flw/domain/iemr/AshaWorker.java | 7 +- .../com/iemr/flw/domain/iemr/CampaignOrs.java | 59 ++ .../iemr/flw/domain/iemr/CbacDetailsImer.java | 330 +++++++ .../flw/domain/iemr/ChildVaccination.java | 13 + .../iemr/ChronicDiseaseVisitEntity.java | 75 ++ .../iemr/flw/domain/iemr/DeliveryOutcome.java | 2 - .../flw/domain/iemr/FilariasisCampaign.java | 66 ++ .../iemr/flw/domain/iemr/HbycChildVisit.java | 2 +- .../com/iemr/flw/domain/iemr/IRSRound.java | 6 + .../flw/domain/iemr/IncentiveActivity.java | 5 +- .../domain/iemr/IncentiveActivityRecord.java | 41 + .../domain/iemr/IncentivePendingActivity.java | 39 + .../com/iemr/flw/domain/iemr/MaaMeeting.java | 13 + .../flw/domain/iemr/MosquitoNetEntity.java | 5 +- .../iemr/flw/domain/iemr/PHCReviewForm.java | 13 + .../flw/domain/iemr/PulsePolioCampaign.java | 60 ++ .../flw/domain/iemr/ScreeningKalaAzar.java | 4 +- .../flw/domain/iemr/ScreeningLeprosy.java | 85 +- .../iemr/flw/domain/iemr/TBConfirmedCase.java | 74 ++ .../flw/domain/iemr/TBConfirmedCaseDTO.java | 29 + .../com/iemr/flw/domain/iemr/TBScreening.java | 33 + .../com/iemr/flw/domain/iemr/TBSuspected.java | 36 + .../domain/iemr/{M_User.java => User.java} | 17 +- .../com/iemr/flw/domain/iemr/UwinSession.java | 3 + .../com/iemr/flw/domain/iemr/VHNDForm.java | 33 + .../com/iemr/flw/domain/iemr/VhncForm.java | 23 + .../abhaBeneficiary/AbhaBeneficiaryDTO.java | 65 ++ .../dto/identity/GetBenRequestHandler.java | 30 + .../com/iemr/flw/dto/iemr/ANCVisitDTO.java | 2 + .../com/iemr/flw/dto/iemr/AbhaRequestDTO.java | 10 + .../flw/dto/iemr/AncCounsellingCareDTO.java | 15 + .../dto/iemr/AncCounsellingCareListDTO.java | 79 ++ .../iemr/AncCounsellingCareResponseDTO.java | 17 + .../dto/iemr/AshaByFacilityRequestDTO.java | 11 + .../java/com/iemr/flw/dto/iemr/CdrDTO.java | 2 + .../flw/dto/iemr/ChronicDiseaseVisitDTO.java | 44 + .../iemr/flw/dto/iemr/DeliveryOutcomeDTO.java | 1 - .../iemr/flw/dto/iemr/DiseaseLeprosyDTO.java | 24 + .../iemr/flw/dto/iemr/EyeCheckupListDTO.java | 17 +- .../flw/dto/iemr/EyeCheckupRequestDTO.java | 1 + .../flw/dto/iemr/FilariasisCampaignDTO.java | 10 + .../dto/iemr/FilariasisCampaignListDTO.java | 30 + .../FilariasisCampaignListResponseDTO.java | 31 + .../flw/dto/iemr/FilariasisResponseDTO.java | 10 + .../java/com/iemr/flw/dto/iemr/HbycDTO.java | 2 +- .../iemr/flw/dto/iemr/IncentiveRecordDTO.java | 32 + .../flw/dto/iemr/MaaMeetingRequestDTO.java | 7 + .../flw/dto/iemr/MaaMeetingResponseDTO.java | 5 + .../java/com/iemr/flw/dto/iemr/MdsrDTO.java | 6 + .../com/iemr/flw/dto/iemr/OrsCampaignDTO.java | 10 + .../iemr/flw/dto/iemr/OrsCampaignListDTO.java | 30 + .../dto/iemr/OrsCampaignListResponseDTO.java | 25 + .../flw/dto/iemr/OrsCampaignResponseDTO.java | 9 + .../flw/dto/iemr/OrsDistributionListDTO.java | 2 +- .../com/iemr/flw/dto/iemr/PaymentItem.java | 18 + .../com/iemr/flw/dto/iemr/PaymentRequest.java | 43 + .../iemr/flw/dto/iemr/PendingActivityDTO.java | 15 + .../java/com/iemr/flw/dto/iemr/Period.java | 19 + .../flw/dto/iemr/PhcReviewMeetingFormDTO.java | 6 + .../iemr/flw/dto/iemr/PolioCampaignDTO.java | 10 + .../flw/dto/iemr/PolioCampaignListDTO.java | 28 + .../iemr/PolioCampaignListResponseDTO.java | 25 + .../dto/iemr/PolioCampaignResponseDTO.java | 9 + .../dto/iemr/TBConfirmedCasesResponseDTO.java | 11 + .../flw/dto/iemr/TBConfirmedRequestDTO.java | 13 + .../com/iemr/flw/dto/iemr/TBScreeningDTO.java | 98 +- .../com/iemr/flw/dto/iemr/TBSuspectedDTO.java | 16 +- .../dto/iemr/UpdateApprovalRequestDTO.java | 14 + .../iemr/UpdateClaimedStatusRequestDTO.java | 11 + .../iemr/flw/dto/iemr/UserServiceRoleDTO.java | 3 + .../com/iemr/flw/dto/iemr/VHNDFormDTO.java | 12 + .../com/iemr/flw/dto/iemr/VerifiedBy.java | 17 + .../com/iemr/flw/dto/iemr/VhncFormDTO.java | 8 + .../com/iemr/flw/masterEnum/GroupName.java | 3 + .../masterEnum/IncentiveApprovalStatus.java | 35 + .../iemr/flw/masterEnum/IncentiveName.java | 139 +++ .../flw/repo/identity/BeneficiaryRepo.java | 48 +- .../iemr/flw/repo/identity/HouseHoldRepo.java | 4 +- .../com/iemr/flw/repo/iemr/ANCVisitRepo.java | 7 +- .../flw/repo/iemr/AncCounsellingCareRepo.java | 13 + .../repo/iemr/AshaSupervisorLoginRepo.java | 85 ++ .../flw/repo/iemr/BenReferDetailsRepo.java | 19 + .../flw/repo/iemr/CbacIemrDetailsRepo.java | 44 + .../java/com/iemr/flw/repo/iemr/CdrRepo.java | 4 +- .../iemr/flw/repo/iemr/ChildRegisterRepo.java | 4 + .../flw/repo/iemr/ChildVaccinationRepo.java | 41 +- .../iemr/ChronicDiseaseVisitRepository.java | 14 + .../flw/repo/iemr/DeliveryOutcomeRepo.java | 2 + .../repo/iemr/DiseaseLeprosyRepository.java | 2 + .../repo/iemr/EligibleCoupleRegisterRepo.java | 5 + .../flw/repo/iemr/EmployeeMasterRepo.java | 12 +- .../flw/repo/iemr/EyeCheckUpVisitRepo.java | 1 + .../iemr/flw/repo/iemr/FacilityLoginRepo.java | 98 ++ .../flw/repo/iemr/FilariasisCampaignRepo.java | 13 + .../com/iemr/flw/repo/iemr/HbncVisitRepo.java | 5 +- .../iemr/IFAFormSubmissionRepository.java | 8 + .../IncentiveActivityLangMappingRepo.java | 3 + .../IncentivePendingActivityRepository.java | 13 + .../flw/repo/iemr/IncentiveRecordRepo.java | 200 +++- .../iemr/flw/repo/iemr/IncentivesRepo.java | 28 +- .../repo/iemr/LeprosyFollowUpRepository.java | 2 +- .../java/com/iemr/flw/repo/iemr/MdsrRepo.java | 5 +- .../iemr/flw/repo/iemr/OrsCampaignRepo.java | 17 + .../com/iemr/flw/repo/iemr/PNCVisitRepo.java | 7 +- .../flw/repo/iemr/PulsePolioCampaignRepo.java | 13 + .../repo/iemr/SupervisorDashboardRepo.java | 111 +++ .../iemr/TBConfirmedTreatmentRepository.java | 17 + .../iemr/flw/repo/iemr/TBScreeningRepo.java | 4 +- .../flw/repo/iemr/UserServiceRoleRepo.java | 18 +- .../flw/service/AbhaBeneficiaryService.java | 12 + .../iemr/flw/service/AbhaTokenService.java | 7 + .../iemr/flw/service/BeneficiaryService.java | 4 +- .../com/iemr/flw/service/CampaignService.java | 24 + .../iemr/flw/service/ChildCareService.java | 6 +- .../flw/service/DiseaseControlService.java | 5 + .../iemr/flw/service/EmployeeMasterInter.java | 6 +- .../flw/service/IFAFormSubmissionService.java | 2 +- .../com/iemr/flw/service/IRSRoundService.java | 2 +- .../flw/service/IncentiveLogicService.java | 35 + .../iemr/flw/service/IncentiveService.java | 11 +- .../iemr/flw/service/MaaMeetingService.java | 173 +++- .../flw/service/MalariaFollowUpService.java | 2 +- .../flw/service/MaternalHealthService.java | 6 +- .../service/SupervisorDashboardService.java | 20 + .../flw/service/TBConfirmedCaseService.java | 16 + .../iemr/flw/service/UwinSessionService.java | 2 + .../flw/service/health/HealthService.java | 517 ++++++++++ .../impl/AbhaBeneficiaryServiceImpl.java | 198 ++++ .../service/impl/AbhaTokenServiceImpl.java | 103 ++ .../impl/AdolescentHealthServiceImpl.java | 4 +- .../flw/service/impl/AshaProfileImpl.java | 150 ++- .../service/impl/BeneficiaryServiceImpl.java | 747 ++++++++------- .../flw/service/impl/CampaignServiceImpl.java | 507 ++++++++++ .../service/impl/ChildCareServiceImpl.java | 812 +++++++++++----- .../flw/service/impl/ChildServiceImpl.java | 75 ++ .../flw/service/impl/CoupleServiceImpl.java | 602 ++++++++---- .../flw/service/impl/CrashLogServiceImpl.java | 2 +- .../service/impl/DeathReportsServiceImpl.java | 177 +++- .../impl/DeliveryOutcomeServiceImpl.java | 244 +++-- .../impl/DiseaseControlServiceImpl.java | 862 +++++++++++++---- .../flw/service/impl/EmployeeMasterImpl.java | 8 +- .../flw/service/impl/FacilityDataService.java | 186 ++++ .../impl/IFAFormSubmissionServiceImpl.java | 65 +- .../flw/service/impl/IRSRoundServiceImpl.java | 4 +- .../flw/service/impl/IncentiveLogicImpl.java | 708 ++++++++++++++ .../service/impl/IncentiveServiceImpl.java | 895 +++++++++++++++--- .../flw/service/impl/InfantServiceImpl.java | 2 +- .../impl/MalariaFollowUpServiceImpl.java | 62 +- .../impl/MaternalHealthServiceImpl.java | 660 ++++++++++--- .../impl/NotificationSchedulerService.java | 10 +- .../flw/service/impl/SammelanServiceImpl.java | 76 +- .../flw/service/impl/SmsSchedulerService.java | 11 +- .../impl/SupervisorDashboardServiceImpl.java | 437 +++++++++ .../impl/TBConfirmedCaseServiceImpl.java | 182 ++++ .../service/impl/TBScreeningServiceImpl.java | 25 +- .../service/impl/TBSuspectedServiceImpl.java | 25 +- .../flw/service/impl/UTPReronaPaymentJob.java | 195 ++++ .../UpdateIncentivePendindDocService.java | 48 + .../flw/service/impl/UserServiceImpl.java | 5 + .../impl/UtpreronaPaymentIntegrationImpl.java | 66 ++ .../service/impl/UwinSessionServiceImpl.java | 72 +- .../impl/VillageLevelFormServiceImpl.java | 210 +++- .../iemr/flw/utils/JwtAuthenticationUtil.java | 18 +- .../flw/utils/JwtUserIdValidationFilter.java | 6 +- src/main/java/com/iemr/flw/utils/JwtUtil.java | 9 - .../com/iemr/flw/utils/LocalDateAdapter.java | 20 + .../iemr/flw/utils/PathTraversalFilter.java | 56 ++ .../utils/http/HTTPRequestInterceptor.java | 2 +- .../com/iemr/flw/utils/redis/RedisConfig.java | 4 +- .../utils/sessionobject/SessionObject.java | 1 - src/main/resources/application.properties | 3 +- 204 files changed, 12455 insertions(+), 1922 deletions(-) delete mode 100644 src/main/environment/common_local.properties create mode 100644 src/main/java/com/iemr/flw/controller/AbhaBeneficiaryController.java create mode 100644 src/main/java/com/iemr/flw/controller/AbhaTokenController.java create mode 100644 src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java create mode 100644 src/main/java/com/iemr/flw/controller/CampaignController.java create mode 100644 src/main/java/com/iemr/flw/controller/health/HealthController.java create mode 100644 src/main/java/com/iemr/flw/controller/version/VersionController.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/AbhaApiResponse.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java rename src/main/java/com/iemr/flw/domain/iemr/{M_User.java => User.java} (91%) create mode 100644 src/main/java/com/iemr/flw/dto/abhaBeneficiary/AbhaBeneficiaryDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/AbhaRequestDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/AshaByFacilityRequestDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/ChronicDiseaseVisitDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListResponseDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/FilariasisResponseDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/OrsCampaignDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListResponseDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/OrsCampaignResponseDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/PaymentItem.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/PaymentRequest.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/PendingActivityDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/Period.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/PolioCampaignDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListResponseDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/PolioCampaignResponseDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/TBConfirmedCasesResponseDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/UpdateApprovalRequestDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/VerifiedBy.java create mode 100644 src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java create mode 100644 src/main/java/com/iemr/flw/masterEnum/IncentiveName.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/AncCounsellingCareRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/CbacIemrDetailsRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/ChronicDiseaseVisitRepository.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/FacilityLoginRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/FilariasisCampaignRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/IncentivePendingActivityRepository.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/OrsCampaignRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/PulsePolioCampaignRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/TBConfirmedTreatmentRepository.java create mode 100644 src/main/java/com/iemr/flw/service/AbhaBeneficiaryService.java create mode 100644 src/main/java/com/iemr/flw/service/AbhaTokenService.java create mode 100644 src/main/java/com/iemr/flw/service/CampaignService.java create mode 100644 src/main/java/com/iemr/flw/service/IncentiveLogicService.java create mode 100644 src/main/java/com/iemr/flw/service/SupervisorDashboardService.java create mode 100644 src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java create mode 100644 src/main/java/com/iemr/flw/service/health/HealthService.java create mode 100644 src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java create mode 100644 src/main/java/com/iemr/flw/service/impl/AbhaTokenServiceImpl.java create mode 100644 src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java create mode 100644 src/main/java/com/iemr/flw/service/impl/FacilityDataService.java create mode 100644 src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java create mode 100644 src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java create mode 100644 src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java create mode 100644 src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java create mode 100644 src/main/java/com/iemr/flw/service/impl/UpdateIncentivePendindDocService.java create mode 100644 src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java create mode 100644 src/main/java/com/iemr/flw/utils/LocalDateAdapter.java create mode 100644 src/main/java/com/iemr/flw/utils/PathTraversalFilter.java diff --git a/.gitignore b/.gitignore index 769653c4f..a4786a90b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ mvnw mvnw.cmd .mvn /logs/ +src/main/environment/common_local.properties diff --git a/pom.xml b/pom.xml index 512a160bb..576c0cdfb 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iemr.common.flw flw-api - 3.10.0 + 3.8.2 war FLW-API @@ -337,6 +337,32 @@ + + io.github.git-commit-id + git-commit-id-maven-plugin + 9.0.2 + + + get-the-git-infos + + revision + + initialize + + + + true + ${project.build.outputDirectory}/git.properties + + ^git.branch$ + ^git.commit.id.abbrev$ + ^git.build.version$ + ^git.build.time$ + + false + false + + org.apache.maven.plugins maven-antrun-plugin @@ -420,4 +446,4 @@ - \ No newline at end of file + diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 347e06a37..238d5f926 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -16,8 +16,7 @@ secondary.datasource.password=@env.DATABASE_IDENTITY_PASSWORD@ secondary.datasource.url=@env.DATABASE_IDENTITY_URL@ secondary.datasource.driver-class-name=com.mysql.jdbc.Driver -springdoc.api-docs.enabled=@env.SWAGGER_UI_ENABLED@ -springdoc.swagger-ui.enabled=@env.SWAGGER_UI_ENABLED@ + #ELK logging file name logging.path=logs/ @@ -37,4 +36,17 @@ sms-username=@env.SMS_USERNAME@ sms-password=@env.SMS_PASSWORD@ send-message-url=@env.SMS_MESSAGE_URL@ -crash.logs.base.path=@env.CRASH_LOGS_PATH@ +#crash.logs.base.path=@env.CRASH_LOGS_PATH@ + +# ABHA Token Config +abha.client.id=@env.ABHA_CLIENT_ID@ +abha.client.secret=@env.ABHA_CLIENT_SECRET@ +abha.token.url=@env.ABHA_TOKEN_URL@ +abha.xcmid=@env.ABHA_XCM_ID@ + +# GovThealth API Config +govthealth.user.details.url=@env.GOVTHEALTH_USER_DETAILS_URL@ +govthealth.user.id=@env.GOVTHEALTH_USER_ID@ +govthealth.password=@env.GOVTHEALTH_PASSWORD@ + + diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index 958a9a193..073091334 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -1,5 +1,5 @@ -fhir-url = ${FHIR_URL} -tm-url = ${TM_URL} +fhir-url = ${FHIR_API} +tm-url = ${TM_API} ##--------------------------------------------## Primary db------------------------------------------------------------------- @@ -15,8 +15,8 @@ secondary.datasource.password=${DATABASE_IDENTITY_PASSWORD} secondary.datasource.url=${DATABASE_IDENTITY_URL} secondary.datasource.driver-class-name=com.mysql.jdbc.Driver -springdoc.api-docs.enabled=true -springdoc.swagger-ui.enabled=true + + #ELK logging file name logging.path=logs/ @@ -35,4 +35,18 @@ sms-password=${SMS_PASSWORD} send-message-url=${SMS_MESSAGE_URL} -crash.logs.base.path=${CRASH_LOGS_PATH} +#crash.logs.base.path=${CRASH_LOGS_PATH} + +# ABHA Token Config +abha.client.id=${ABHA_CLIENT_ID} +abha.client.secret=${ABHA_CLIENT_SECRET} +abha.token.url=${ABHA_TOKEN_URL} +abha.xcmid=${ABHA_XCM_ID} + +# GovThealth API Config +govthealth.user.details.url=${GOVTHEALTH_USER_DETAILS_URL} +govthealth.user.id=${GOVTHEALTH_USER_ID} +govthealth.password=${GOVTHEALTH_PASSWORD} + + + diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 51873ab65..3c679d09c 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -38,6 +38,12 @@ send-message-url= crash.logs.base.path= +# ABHA Token Config +abha.client.id= +abha.client.secret= +abha.token.url= +abha.xcmid= + diff --git a/src/main/environment/common_local.properties b/src/main/environment/common_local.properties deleted file mode 100644 index 6e5bdd00c..000000000 --- a/src/main/environment/common_local.properties +++ /dev/null @@ -1,45 +0,0 @@ -spring.main.banner-mode=off -spring.data.jpa.repositories.enabled=true -#spring.jpa.hibernate.ddl-auto=none - -# Naming strategies -spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl -spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl - -# The SQL dialect makes Hibernate generate better SQL for the chosen database -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect - -#Below lines are added for security reasons - -spring.session.store-type=redis -spring.redis.password= -spring.redis.port=6379 - -## Below values are needed for extending the expiry time and extend expiry time. -iemr.extend.expiry.time=true -iemr.session.expiry.time=7200 -enableIPValidation=false - -#logging.pattern.level=DEBUG -logging.level.root=INFO -logging.level.org.springframework.web=INFO -logging.level.org.hibernate=INFO -logging.level.com.iemr=DEBUG -logging.level.org.springframework=INFO - -spring.datasource.tomcat.initial-size=5 -spring.datasource.tomcat.max-idle=15 -spring.datasource.tomcat.max-active=30 -spring.datasource.tomcat.min-idle=5 -spring.datasource.tomcat.min-evictable-idle-time-millis=15000 -spring.datasource.tomcat.remove-abandoned=true -spring.datasource.tomcat.logAbandoned=true -spring.datasource.continue-on-error=true -spring.datasource.tomcat.remove-abandoned-timeout=600 -door-to-door-page-size=10 - -#Get-HRP-Status -get-HRP-Status=ANC/getHRPStatus - -#Get Beneficiary ABHA -getHealthID=healthID/getBenhealthID diff --git a/src/main/java/com/iemr/flw/controller/AbhaBeneficiaryController.java b/src/main/java/com/iemr/flw/controller/AbhaBeneficiaryController.java new file mode 100644 index 000000000..8025de558 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/AbhaBeneficiaryController.java @@ -0,0 +1,54 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.domain.iemr.AdolescentHealth; +import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.AbhaRequestDTO; +import com.iemr.flw.service.AbhaBeneficiaryService; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/UserRegistration") +public class AbhaBeneficiaryController { + @Autowired + private AbhaBeneficiaryService abhaBeneficiaryService; + + private final org.slf4j.Logger logger = LoggerFactory.getLogger(AbhaBeneficiaryController.class); + + + + @RequestMapping(value = "/GetUserDetailsByAyushmanCardNo",method = RequestMethod.POST) + public ResponseEntity> getAllAdolescentHealth(@RequestBody AbhaRequestDTO request ) { + Map response = new HashMap<>(); + try { + if(request.getCardNo()!=null){ + Object abhaBeneficiaryDTOList = abhaBeneficiaryService.getBeneficiaryByAbha(request); + + if (abhaBeneficiaryDTOList != null ) { + response.put("statusCode",200); + response.put("data", abhaBeneficiaryDTOList); + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } + + } catch (Exception e) { + logger.error("Error in get data : " + e); + response.put("statusCode",5000); + response.put("error","Error in get data : " + e); + + } + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/iemr/flw/controller/AbhaTokenController.java b/src/main/java/com/iemr/flw/controller/AbhaTokenController.java new file mode 100644 index 000000000..5197ddf23 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/AbhaTokenController.java @@ -0,0 +1,40 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.service.AbhaTokenService; +import com.iemr.flw.utils.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping(value = "/abha", headers = "Authorization") +public class AbhaTokenController { + + private final Logger logger = LoggerFactory.getLogger(AbhaTokenController.class); + + @Autowired + private AbhaTokenService abhaTokenService; + + @Operation(summary = "Get ABHA access token") + @PostMapping("/token") + public ResponseEntity getAbhaToken( + @RequestHeader(value = "Authorization") String authorization) { + try { + Map tokenResponse = abhaTokenService.getAbhaToken(); + return new ResponseEntity<>( + new ApiResponse(true, null, tokenResponse), HttpStatus.OK); + } catch (Exception e) { + logger.error("Error fetching ABHA token: " + e.getMessage()); + return new ResponseEntity<>( + new ApiResponse(false, "Error fetching ABHA token: " + e.getMessage(), null), + HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/src/main/java/com/iemr/flw/controller/AshaProfileController.java b/src/main/java/com/iemr/flw/controller/AshaProfileController.java index 1bda44990..2d02ce231 100644 --- a/src/main/java/com/iemr/flw/controller/AshaProfileController.java +++ b/src/main/java/com/iemr/flw/controller/AshaProfileController.java @@ -1,35 +1,21 @@ package com.iemr.flw.controller; import com.iemr.flw.domain.iemr.AshaWorker; -import com.iemr.flw.domain.iemr.M_User; -import com.iemr.flw.dto.iemr.UserServiceRoleDTO; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.AshaProfileService; import com.iemr.flw.service.EmployeeMasterInter; -import com.iemr.flw.service.UserService; import io.lettuce.core.dynamic.annotation.Param; import com.iemr.flw.utils.JwtUtil; -import io.swagger.v3.oas.annotations.Operation; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import com.iemr.flw.utils.JwtAuthenticationUtil; -import com.iemr.flw.utils.JwtUtil; -import com.iemr.flw.utils.exception.IEMRException; -import io.jsonwebtoken.Claims; -import io.swagger.v3.oas.annotations.Operation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; -import java.util.Objects; @RestController @RequestMapping(value = "/asha", produces = "application/json") @@ -76,18 +62,18 @@ public ResponseEntity> getProfile(HttpServletRequest request try { String jwtFromHeader = request.getHeader("JwtToken"); - // Validate JWT header presence -// if (jwtFromHeader == null || jwtFromHeader.trim().isEmpty()) { -// response.put("statusCode", 401); -// response.put("status", "Unauthorized"); -// response.put("errorMessage", "JWT token is missing"); -// return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); -// } +// Validate JWT header presence + if (jwtFromHeader == null || jwtFromHeader.trim().isEmpty()) { + response.put("statusCode", 401); + response.put("status", "Unauthorized"); + response.put("errorMessage", "JWT token is missing"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); + } // Extract and validate user ID from JWT - // int userId = jwtUtil.extractUserId(jwtFromHeader); // Make sure this returns 0 or throws for invalid token + int userId = jwtUtil.extractUserId(jwtFromHeader); // Make sure this returns 0 or throws for invalid token - if (employeeId == 0) { + if (userId == 0) { response.put("statusCode", 401); response.put("status", "Unauthorized"); response.put("errorMessage", "Invalid JWT token"); @@ -95,7 +81,7 @@ public ResponseEntity> getProfile(HttpServletRequest request } // Business logic - AshaWorker ashaWorker = ashaProfileService.getProfileData(employeeId); + AshaWorker ashaWorker = ashaProfileService.getProfileData(userId); logger.info("Asha Profile"+ashaWorker); response.put("statusCode", 200); diff --git a/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java new file mode 100644 index 000000000..3f840f614 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java @@ -0,0 +1,123 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.iemr.AshaByFacilityRequestDTO; +import com.iemr.flw.dto.iemr.UpdateApprovalRequestDTO; +import com.iemr.flw.service.SupervisorDashboardService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.response.OutputResponse; +import io.swagger.v3.oas.annotations.Operation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +@RestController +@RequestMapping("/ashaSupervisor") +public class AshaSupervisorIncentiveApproval { + + @Autowired + private SupervisorDashboardService supervisorDashboardService; + + @Autowired + private JwtUtil jwtUtil; + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + + @PostMapping("/getAshaListByFacility") + public ResponseEntity getAshaListByFacility( + @RequestBody AshaByFacilityRequestDTO request, + @RequestHeader(value = "JwtToken") String token) { + + try { + + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("UNAUTHORIZED"); + } + + Map result = supervisorDashboardService.getAshasAtFacility( + jwtUtil.extractUserId(token), + request.getFacilityId(), + request.getMonth(), + request.getYear(), + request.getApprovalStatus() + ); + + logger.info("result {}", result); + + return ResponseEntity.status(HttpStatus.OK).body(result); + + } catch (Exception e) { + + logger.error("Error in getAshaListByFacility", e); + + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Server error: " + e.getMessage()); + } + } + + + + + @Operation(summary = "Get comprehensive ASHA Supervisor dashboard with facilities, ASHAs, villages and incentive data") + @PostMapping("/dashboard") + public String getSupervisorDashboard(@RequestBody AshaByFacilityRequestDTO request,@RequestHeader(value = "JwtToken") String token ) { + OutputResponse response = new OutputResponse(); + + try { + if(token!=null){ + String result = supervisorDashboardService.getSupervisorDashboard(jwtUtil.extractUserId(token),request.getMonth(),request.getYear()); + response.setResponse(result); + } + + } catch (Exception e) { + logger.error("getSupervisorDashboard failed: " + e.getMessage(), e); + response.setError(e); + } + return response.toString(); + } + + @PostMapping("/updateApprovalStatus") + public ResponseEntity updateApprovalStatus( + @RequestBody UpdateApprovalRequestDTO request, + @RequestHeader(value = "JwtToken") String token) { + + try { + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("UNAUTHORIZED"); + } + + int updatedRows = supervisorDashboardService.updateApprovalStatus( + request.getAshaId(), + request.getMonth(), + request.getYear(), + request.getApprovalStatus(), + request.getIncentiveIds(), + request.getReason(), + request.getOtherReason(), + token + ); + + Map response = new HashMap<>(); + response.put("statusCode", 200); + response.put("updatedRecords", updatedRows); + + return ResponseEntity.ok(response); + + } catch (Exception e) { + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Server error: " + e.getMessage()); + } + } + + +} diff --git a/src/main/java/com/iemr/flw/controller/BeneficiaryController.java b/src/main/java/com/iemr/flw/controller/BeneficiaryController.java index dd083840d..d439fbf5d 100644 --- a/src/main/java/com/iemr/flw/controller/BeneficiaryController.java +++ b/src/main/java/com/iemr/flw/controller/BeneficiaryController.java @@ -40,10 +40,13 @@ public class BeneficiaryController { @Autowired private MdaFormSubmissionService mdaFormSubmissionService; + @Autowired + private JwtUtil jwtUtil; + @RequestMapping(value = "/getBeneficiaryData", method = RequestMethod.POST) @Operation(summary = "get beneficiary data for given user ") public String getBeneficiaryDataByAsha(@RequestBody GetBenRequestHandler requestDTO, - @RequestHeader(value = "Authorization") String authorization) { + @RequestHeader(value = "Authorization") String authorization) { OutputResponse response = new OutputResponse(); try { @@ -65,8 +68,9 @@ public String getBeneficiaryDataByAsha(@RequestBody GetBenRequestHandler request return response.toString(); } + @RequestMapping(value = {"/eye_surgery/saveAll"}, method = RequestMethod.POST) - public ResponseEntity saveEyeSurgery(@RequestBody List eyeCheckupRequestDTOS) { + public ResponseEntity saveEyeSurgery(@RequestBody List eyeCheckupRequestDTOS, @RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("Eye Checkup Save Request: {}", eyeCheckupRequestDTOS); @@ -77,7 +81,7 @@ public ResponseEntity saveEyeSurgery(@RequestBody List return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); } - String responseObject = beneficiaryService.saveEyeCheckupVsit(eyeCheckupRequestDTOS); + String responseObject = beneficiaryService.saveEyeCheckupVsit(eyeCheckupRequestDTOS, token); if (responseObject != null) { response.put("statusCode", HttpStatus.OK.value()); @@ -91,47 +95,102 @@ public ResponseEntity saveEyeSurgery(@RequestBody List } catch (Exception e) { logger.error("Error saving eye checkup visit:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + return ResponseEntity.ok(response); } } - @RequestMapping(value = {"/eye_surgery/getAll"}, method = RequestMethod.POST) - public ResponseEntity getAllEyeSurgery(@RequestBody GetBenRequestHandler request) { + public ResponseEntity getAllEyeSurgery(@RequestBody GetBenRequestHandler request, @RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("Eye Checkup Get Request: {}", request); try { - List responseObject = beneficiaryService.getEyeCheckUpVisit(request); + List responseObject = beneficiaryService.getEyeCheckUpVisit(request, token); if (responseObject != null && !responseObject.isEmpty()) { response.put("statusCode", HttpStatus.OK.value()); response.put("data", responseObject); return ResponseEntity.ok(response); } else { - response.put("statusCode", HttpStatus.NOT_FOUND.value()); + response.put("statusCode", 5000); response.put("message", "No records found"); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + return ResponseEntity.ok(response); } } catch (Exception e) { logger.error("Error fetching eye checkup visit:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + return ResponseEntity.ok(response); } } - @RequestMapping(value = "/ifa/saveAll",method = RequestMethod.POST) - public ResponseEntity saveFormData(@RequestBody List requests) { - String message = ifaFormSubmissionService.saveFormData(requests); - return ResponseEntity.ok(Map.of("success", true, "message", message)); + @RequestMapping(value = "/ifa/saveAll", method = RequestMethod.POST) + public ResponseEntity saveIfaFormData( + @RequestBody List requests, + @RequestHeader(value = "JwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + logger.info("IFA Save Request: {}", requests); + + try { + + if (requests == null || requests.isEmpty()) { + + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Request body cannot be empty"); + + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(response); + } + if (token != null) { + String message = + ifaFormSubmissionService.saveFormData(requests, jwtUtil.extractUserId(token)); + + if (message != null) { + + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", message); + + return ResponseEntity.ok(response); + + } else { + + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save records"); + + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(response); + } + } else { + response.put("statusCode", HttpStatus.UNAUTHORIZED.value()); + response.put("message", "UNAUTHORIZED"); + + return ResponseEntity + .status(HttpStatus.UNAUTHORIZED) + .body(response); + } + + + } catch (Exception e) { + + logger.error("Error saving IFA records:", e); + + response.put("statusCode", 5000); + response.put("errorMessage", e.getMessage()); + + return ResponseEntity.ok(response); + + } } - @RequestMapping(value = "ifa/getAll",method = RequestMethod.POST) + @RequestMapping(value = "ifa/getAll", method = RequestMethod.POST) public ResponseEntity getFormData(@RequestBody GetBenRequestHandler getBenRequestHandler) { var data = ifaFormSubmissionService.getFormData(getBenRequestHandler); return ResponseEntity.ok(Map.of("success", true, "message", "Data fetched successfully", "data", data)); @@ -139,15 +198,15 @@ public ResponseEntity getFormData(@RequestBody GetBenRequestHandler getBenReq @RequestMapping(value = "/mda/saveAll", method = RequestMethod.POST) public ResponseEntity saveFormData(@RequestBody List requests, - @RequestHeader(value = "Authorization") String authorization) { + @RequestHeader(value = "Authorization") String authorization) { String message = mdaFormSubmissionService.saveFormData(requests); return ResponseEntity.ok(Map.of("success", true, "message", message)); } @RequestMapping(value = "/mda/getAll", method = RequestMethod.POST) public ResponseEntity getFormDataByCreatedBy(@RequestBody Map request, - @RequestHeader(value = "Authorization") String authorization) { - String userName = request.get("userName") ; + @RequestHeader(value = "Authorization") String authorization) { + String userName = request.get("userName"); var data = mdaFormSubmissionService.getFormDataByUserName(userName); return ResponseEntity.ok(Map.of("success", true, "message", "Data fetched successfully", "data", data)); } diff --git a/src/main/java/com/iemr/flw/controller/CampaignController.java b/src/main/java/com/iemr/flw/controller/CampaignController.java new file mode 100644 index 000000000..f5f13d698 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/CampaignController.java @@ -0,0 +1,360 @@ +package com.iemr.flw.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.iemr.flw.domain.iemr.CampaignOrs; +import com.iemr.flw.domain.iemr.FilariasisCampaign; +import com.iemr.flw.domain.iemr.PulsePolioCampaign; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.service.CampaignService; +import com.iemr.flw.utils.exception.IEMRException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.sql.Timestamp; +import java.util.*; + +@RestController +@RequestMapping(value = "/campaign") +public class CampaignController { + private final Logger logger = LoggerFactory.getLogger(CampaignController.class); + + @Autowired + private CampaignService campaignService; + + @PostMapping("/ors/distribution/saveAll") + public ResponseEntity> saveOrsDistribution( + @RequestPart("formDataJson") String fields, + @RequestHeader("jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + + // Validate input + if (fields == null || fields.trim().isEmpty()) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Form data is required"); + return ResponseEntity.badRequest().body(response); + } + + // Parse JSON to DTO + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + OrsCampaignDTO requestDTO = objectMapper.readValue(fields, OrsCampaignDTO.class); + + // Validate fields + if (requestDTO.getFields() == null) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Campaign fields are required"); + return ResponseEntity.badRequest().body(response); + } + + logger.info("Parsed DTO - Start Date: {}, End Date: {}, Families: {}, Photos: {}", + requestDTO.getFields().getStartDate(), + requestDTO.getFields().getEndDate(), + requestDTO.getFields().getNumberOfFamilies(), + requestDTO.getFields().getCampaignPhotos() + ); + + // Create DTO + OrsCampaignDTO campaignDTO = new OrsCampaignDTO(); + campaignDTO.setFields(requestDTO.getFields()); + + List orsCampaignDTOList = Collections.singletonList(campaignDTO); + + // Save to database + List result = campaignService.saveOrsCampaign(orsCampaignDTOList, token); + + if (result != null && !result.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "Campaign saved successfully"); + response.put("data", result); + return ResponseEntity.status(HttpStatus.OK).body(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save campaign"); + return ResponseEntity.badRequest().body(response); + } + + } catch (JsonProcessingException e) { + logger.error("JSON parsing error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Invalid JSON format"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (IEMRException e) { + logger.error("Business logic error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (Exception e) { + logger.error("Error saving ORS distribution: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "Internal server error occurred"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @RequestMapping(value = "ors/distribution/getAll", method = RequestMethod.POST) + public ResponseEntity> getAllOrsDistribution(@RequestHeader(value = "jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + List result = campaignService.getOrsCampaign(token); + + + if (result != null) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("data", result); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "No records found"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + + } catch (Exception e) { + logger.error("Error save ors distribution :", e.getMessage()); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @PostMapping("/polio/campaign/saveAll") + public ResponseEntity> savePolioCampaign( + @RequestPart("formDataJson") String fields, + @RequestHeader("jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + logger.info("Received polio campaign data"); + + // Validate input + if (fields == null || fields.trim().isEmpty()) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Form data is required"); + return ResponseEntity.badRequest().body(response); + } + + // Parse JSON to DTO + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + PolioCampaignDTO requestDTO = objectMapper.readValue(fields, PolioCampaignDTO.class); + + // Validate fields + if (requestDTO.getFields() == null) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Campaign fields are required"); + return ResponseEntity.badRequest().body(response); + } + + logger.info("Parsed DTO - Start Date: {}, End Date: {}, Families: {}, Individuals: {}, Photos: {}", + requestDTO.getFields().getStartDate(), + requestDTO.getFields().getEndDate(), + requestDTO.getFields().getNumberOfChildren(), + + requestDTO.getFields().getCampaignPhotos() + ); + + // Create DTO + PolioCampaignDTO campaignDTO = new PolioCampaignDTO(); + campaignDTO.setFields(requestDTO.getFields()); + + List polioCampaignDTOList = Collections.singletonList(campaignDTO); + + // Save to database + List result = campaignService.savePolioCampaign(polioCampaignDTOList, token); + + if (result != null && !result.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "polio campaign saved successfully"); + response.put("data", result); + return ResponseEntity.status(HttpStatus.OK).body(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save Polio campaign"); + return ResponseEntity.badRequest().body(response); + } + + } catch (JsonProcessingException e) { + logger.error("JSON parsing error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Invalid JSON format"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (IEMRException e) { + logger.error("Business logic error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (Exception e) { + logger.error("Error saving filariasis campaign: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "Internal server error occurred"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @RequestMapping(value = "polio/campaign/getAll", method = RequestMethod.POST) + public ResponseEntity> getAllPolioCampaign(@RequestHeader(value = "jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + List result = campaignService.getPolioCampaign(token); + + + if (result != null) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("data", result); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "No records found"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + + } catch (Exception e) { + logger.error("Error save ors distribution :", e.getMessage()); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @PostMapping("/filariasis/campaign/saveAll") + public ResponseEntity> saveFilariasisCampaign( + @RequestPart("formDataJson") String fields, + @RequestHeader("jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + logger.info("Received polio campaign data"); + + // Validate input + if (fields == null || fields.trim().isEmpty()) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Form data is required"); + return ResponseEntity.badRequest().body(response); + } + + // Parse JSON to DTO + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + FilariasisCampaignDTO requestDTO = objectMapper.readValue(fields, FilariasisCampaignDTO.class); + + // Validate fields + if (requestDTO.getFields() == null) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Campaign fields are required"); + return ResponseEntity.badRequest().body(response); + } + + logger.info("Parsed DTO - Start Date: {}, End Date: {}, Families: {}, Individuals: {}, Photos: {}", + requestDTO.getFields().getStartDate(), + requestDTO.getFields().getEndDate(), + requestDTO.getFields().getNumberOfIndividuals(), + requestDTO.getFields().getNumberOfIndividuals(), + + requestDTO.getFields().getMdaPhotos() + ); + + // Create DTO + FilariasisCampaignDTO campaignDTO = new FilariasisCampaignDTO(); + campaignDTO.setFields(requestDTO.getFields()); + + List filariasisCampaignDTOS = Collections.singletonList(campaignDTO); + + + // Save to database + List result = campaignService.saveFilariasisCampaign(filariasisCampaignDTOS, token); + + if (result != null && !result.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "filariasis campaign saved successfully"); + response.put("data", result); + return ResponseEntity.status(HttpStatus.OK).body(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save filariasis campaign"); + return ResponseEntity.badRequest().body(response); + } + + } catch (JsonProcessingException e) { + logger.error("JSON parsing error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Invalid JSON format"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (IEMRException e) { + logger.error("Business logic error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (Exception e) { + logger.error("Error saving filariasis campaign: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "Internal server error occurred"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @RequestMapping(value = "filariasis/campaign/getAll", method = RequestMethod.POST) + public ResponseEntity> getAllFilariasisCampaign(@RequestHeader(value = "jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + List result = campaignService.getAllFilariasisCampaign(token); + + + if (result != null) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("data", result); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "No records found"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + + } catch (Exception e) { + logger.error("Error save ors distribution :", e.getMessage()); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } +} diff --git a/src/main/java/com/iemr/flw/controller/ChildCareController.java b/src/main/java/com/iemr/flw/controller/ChildCareController.java index d5e4335f8..bbc9cba2f 100644 --- a/src/main/java/com/iemr/flw/controller/ChildCareController.java +++ b/src/main/java/com/iemr/flw/controller/ChildCareController.java @@ -7,14 +7,19 @@ import com.iemr.flw.domain.iemr.HbncVisit; import com.iemr.flw.domain.iemr.IfaDistribution; import com.iemr.flw.domain.iemr.SamVisitResponseDTO; +import com.iemr.flw.domain.iemr.UserServiceRole; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.ChildCareService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; import com.iemr.flw.utils.response.OutputResponse; import io.swagger.v3.oas.annotations.Operation; import jakarta.mail.Multipart; +import org.checkerframework.checker.units.qual.A; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -37,10 +42,18 @@ public class ChildCareController { @Autowired private ChildCareService childCareService; + @Autowired + private UserService userService; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; @Operation(summary = "save HBYC details") @RequestMapping(value = {"/hbycVisit/saveAll"}, method = {RequestMethod.POST}) public String saveHbycRecords(@RequestBody List hbycDTOs, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "JwtToken") String token) { ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); // Pretty print @@ -92,25 +105,27 @@ public String getHbycRecords(@RequestBody GetBenRequestHandler requestDTO) { @PostMapping("/hbncVisit/saveAll") public String saveHBNCVisit(@RequestBody List hbncRequestDTOs, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "jwtToken") String jwtToken) { OutputResponse response = new OutputResponse(); try { if (!hbncRequestDTOs.isEmpty()) { logger.info("Saving HBNC details at: " + new Timestamp(System.currentTimeMillis())); + if(jwtToken!=null){ + String result = childCareService.saveHBNCDetails(hbncRequestDTOs,jwtUtil.extractUserId(jwtToken)); // <-- actual save - String result = childCareService.saveHBNCDetails(hbncRequestDTOs); // <-- actual save + if (result != null) + response.setResponse(result); + else + response.setError(500, "Failed to save HBNC visit data."); + } - if (result != null) - response.setResponse(result); - else - response.setError(500, "Failed to save HBNC visit data."); } else { response.setError(400, "Empty request list."); } } catch (Exception e) { logger.error("Error saving HBNC visit: ", e); - response.setError(500, "Server error: " + e.getMessage()); + response.setError(5000, "Server error: " + e.getMessage()); } return response.toString(); } @@ -146,7 +161,7 @@ public ResponseEntity>> getHBNCVisit } catch (Exception e) { logger.error("Exception in fetching HBNC visits", e); - response.setStatusCode(500); + response.setStatusCode(5000); response.setStatus("Failed"); response.setErrorMessage("Internal Server Error: " + e.getMessage()); response.setData(null); @@ -228,7 +243,7 @@ public String getChildVaccinationDetails(@RequestParam(value = "category") Strin return response.toString(); } @RequestMapping(value = {"/sam/saveAll"}, method = RequestMethod.POST) - public ResponseEntity saveSevereAcuteMalnutrition(@RequestBody List samRequest) { + public ResponseEntity saveSevereAcuteMalnutrition(@RequestBody List samRequest,@RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("SAM Request: {}", samRequest); @@ -240,21 +255,30 @@ public ResponseEntity saveSevereAcuteMalnutrition(@RequestBody List s } - String responseObject = childCareService.saveSamDetails(samRequest); - - if (responseObject != null) { - response.put("statusCode", HttpStatus.OK.value()); - response.put("message", responseObject); - return ResponseEntity.ok(response); - } else { - response.put("statusCode", HttpStatus.BAD_REQUEST.value()); - response.put("message", "Failed to save SAM details"); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + if(token!=null){ + Integer userId = jwtUtil.extractUserId(token); + String userName = userService.getUserDetail(userId).getUserName(); + String responseObject = childCareService.saveSamDetails(samRequest,userId,userName); + + if (responseObject != null) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", responseObject); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save SAM details"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + }else { + response.put("statusCode", HttpStatus.UNAUTHORIZED.value()); + response.put("message", "Invalid token"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); } + } catch (Exception e) { logger.error("Error saving SAM details:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode",5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } @@ -272,14 +296,14 @@ public ResponseEntity getAllSevereAcuteMalnutrition(@RequestBody GetBenReques response.put("data", responseObject); return ResponseEntity.ok(response); } else { - response.put("statusCode", HttpStatus.NOT_FOUND.value()); + response.put("statusCode", HttpStatus.OK.value()); response.put("message", "No SAM records found"); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + return ResponseEntity.status(HttpStatus.NO_CONTENT).body(response); } } catch (Exception e) { logger.error("Error fetching SAM records:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } @@ -287,7 +311,7 @@ public ResponseEntity getAllSevereAcuteMalnutrition(@RequestBody GetBenReques @RequestMapping(value = {"/ors/saveAll"}, method = RequestMethod.POST) - public ResponseEntity saveOrsDistribution(@RequestBody List orsDistributionDTOS) { + public ResponseEntity saveOrsDistribution(@RequestBody List orsDistributionDTOS,@RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("ORS Request: {}", orsDistributionDTOS); @@ -297,22 +321,29 @@ public ResponseEntity saveOrsDistribution(@RequestBody List getAllOrDistribution(@RequestBody GetBenRequestHandler response.put("data", responseObject); return ResponseEntity.ok(response); } else { - response.put("statusCode", HttpStatus.NOT_FOUND.value()); + response.put("statusCode", 5000); response.put("message", "No ORS records found"); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } } catch (Exception e) { logger.error("Error fetching ORS records:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } @@ -346,7 +377,7 @@ public ResponseEntity getAllOrDistribution(@RequestBody GetBenRequestHandler @RequestMapping(value = {"/ifa/saveAll"}, method = RequestMethod.POST) - public ResponseEntity saveIfDistribution(@RequestBody List ifaDistributionDTOS) { + public ResponseEntity saveIfDistribution(@RequestBody List ifaDistributionDTOS,@RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("IFA Request: {}", ifaDistributionDTOS); @@ -356,22 +387,29 @@ public ResponseEntity saveIfDistribution(@RequestBody List responseObject = childCareService.saveAllIfa(ifaDistributionDTOS,userId); + + if (responseObject != null && !responseObject.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "IFA saved successfully"); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save IFA details"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + }else { + response.put("statusCode", HttpStatus.UNAUTHORIZED.value()); + response.put("message", "Invalid token"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); + } - List responseObject = childCareService.saveAllIfa(ifaDistributionDTOS); - - if (responseObject != null && !responseObject.isEmpty()) { - response.put("statusCode", HttpStatus.OK.value()); - response.put("message", "IFA saved successfully"); - return ResponseEntity.ok(response); - } else { - response.put("statusCode", HttpStatus.BAD_REQUEST.value()); - response.put("message", "Failed to save IFA details"); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); - } } catch (Exception e) { logger.error("Error saving IFA:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } @@ -397,7 +435,7 @@ public ResponseEntity getIfaDistribution(@RequestBody GetBenRequestHandler re } catch (Exception e) { logger.error("Error fetching IFA records:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } diff --git a/src/main/java/com/iemr/flw/controller/DeathReportsController.java b/src/main/java/com/iemr/flw/controller/DeathReportsController.java index f5317a8bc..e8b50de90 100644 --- a/src/main/java/com/iemr/flw/controller/DeathReportsController.java +++ b/src/main/java/com/iemr/flw/controller/DeathReportsController.java @@ -84,8 +84,8 @@ public String getCdrRecords(@RequestBody GetBenRequestHandler requestDTO, logger.info("fetching All CDR Details for user: " + requestDTO.getAshaId()); if (requestDTO != null) { List result = deathReportsService.getCdrRecords(requestDTO); - Gson gson = new GsonBuilder() - .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format + Gson gson = new GsonBuilder()// Set the desired date format + .setDateFormat("MMM dd, yyyy h:mm:ss a") .create(); String s = gson.toJson(result); if (s != null) @@ -111,8 +111,8 @@ public String getMdsrRecords(@RequestBody GetBenRequestHandler requestDTO, logger.info("fetching All MDSR Details for user: " + requestDTO.getAshaId()); if (requestDTO != null) { List result = deathReportsService.getMdsrRecords(requestDTO); - Gson gson = new GsonBuilder() - .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format + Gson gson = new GsonBuilder()// Set the desired date format + .setDateFormat("MMM dd, yyyy h:mm:ss a") .create(); String s = gson.toJson(result); if (s != null) diff --git a/src/main/java/com/iemr/flw/controller/DiseaseControlController.java b/src/main/java/com/iemr/flw/controller/DiseaseControlController.java index 2f5d42644..764ebeaf6 100644 --- a/src/main/java/com/iemr/flw/controller/DiseaseControlController.java +++ b/src/main/java/com/iemr/flw/controller/DiseaseControlController.java @@ -34,11 +34,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.LinkedHashMap; @@ -67,12 +63,12 @@ public ResponseEntity> saveMalaria(@RequestBody MalariaDTO m response.put("data", diseaseControlService.saveMalaria(malariaDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -90,12 +86,12 @@ public ResponseEntity> saveKalaAzar(@RequestBody KalaAzarDTO response.put("data", diseaseControlService.saveKalaAzar(kalaAzarDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -112,12 +108,12 @@ public ResponseEntity> saveAESJE(@RequestBody AesJeDTO aesJe response.put("data", diseaseControlService.saveAES(aesJeDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -134,12 +130,12 @@ public ResponseEntity> saveFilaria(@RequestBody FilariaDTO f response.put("data", diseaseControlService.saveFilaria(filariaDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -155,12 +151,12 @@ public ResponseEntity> saveLeprosy(@RequestBody LeprosyDTO l response.put("data", diseaseControlService.saveLeprosy(leprosyDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -179,11 +175,11 @@ public ResponseEntity> saveLeprosyFollowUP(@RequestBody List response.put("message", "All follow-ups saved successfully"); } else { response.put("message", "Invalid request - no follow-up data"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -207,15 +203,17 @@ public ResponseEntity> getAllLeprosy( response.put("data", result); // ← Put list directly, no gson.toJson() } else { response.put("message", "No record found"); - response.put("statusCode", 404); + response.put("statusCode", 5000); } } else { response.put("message", "Invalid request - userName required"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { + logger.info("Fail leprosy: "+e.getMessage()); + logger.info("Fail leprosy full error: "+e); response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); // ← Spring serializes the whole map } @@ -237,15 +235,17 @@ public ResponseEntity> getAllLeprosyFollowUp( response.put("data", result); // ← Put list directly, no gson.toJson() } else { response.put("message", "No record found"); - response.put("statusCode", 404); + response.put("statusCode", 5000); } } else { response.put("message", "Invalid request - userName required"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { + logger.info("Fail leprosy followUp: "+e.getMessage()); + logger.info("Fail leprosy full error: "+e); response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); // ← Spring serializes the whole map } @@ -260,8 +260,10 @@ public ResponseEntity> getAllData( response.put("data", diseaseControlService.getAllScreeningData(getDiseaseRequestHandler)); } catch (Exception e) { + logger.info("getAllDisease "+e.getMessage()); + logger.info("Fail getAllDisease full error: "+e); response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); } @@ -314,5 +316,63 @@ public ResponseEntity> getAllMobilizationMosquitoNet(@Reques return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } } + @RequestMapping(value = "cdtfVisit/saveAll", method = RequestMethod.POST) + public ResponseEntity> saveVisit( + @RequestBody List requestList,@RequestHeader(value = "JwtToken") String token) { + + Map response = new LinkedHashMap<>(); + logger.info("Chronic Disease Visit Save Request: {}", requestList); + + try { + List savedList = + diseaseControlService.saveChronicDiseaseVisit(requestList,token); + + if (savedList != null && !savedList.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "Data saved successfully"); + response.put("data", savedList); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "No data saved"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + + } catch (Exception e) { + logger.error("Error saving Chronic Disease Visit :", e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + @RequestMapping(value = "cdtfVisit/getAll", method = RequestMethod.POST) + public ResponseEntity> getVisitDetails( + @RequestBody GetBenRequestHandler getBenRequestHandler) { + + Map response = new LinkedHashMap<>(); + + try { + List result = + diseaseControlService.getCdtfVisits(getBenRequestHandler); + + if (result != null && !result.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("data", result); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.NOT_FOUND.value()); + response.put("message", "No records found"); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + } + + } catch (Exception e) { + logger.error("Error fetching Chronic Disease Visit :", e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/controller/GeneralOPDController.java b/src/main/java/com/iemr/flw/controller/GeneralOPDController.java index 5e7823df3..c683a9be5 100644 --- a/src/main/java/com/iemr/flw/controller/GeneralOPDController.java +++ b/src/main/java/com/iemr/flw/controller/GeneralOPDController.java @@ -77,7 +77,7 @@ public ResponseEntity> getBeneficiaryDataByAsha(@RequestBody } catch (Exception e) { logger.error("Error in get data : " + e); - response.put("status", 500); + response.put("statusCode", 5000); response.put("message", "Error in get data : " + e); } return ResponseEntity.ok(response); diff --git a/src/main/java/com/iemr/flw/controller/IRSRoundController.java b/src/main/java/com/iemr/flw/controller/IRSRoundController.java index 4425cdeb7..77047f89c 100644 --- a/src/main/java/com/iemr/flw/controller/IRSRoundController.java +++ b/src/main/java/com/iemr/flw/controller/IRSRoundController.java @@ -3,7 +3,10 @@ import com.iemr.flw.domain.iemr.IRSRound; import com.iemr.flw.dto.iemr.IRSRoundDTO; import com.iemr.flw.dto.iemr.IRSRoundListDTO; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.IRSRoundService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; import com.iemr.flw.utils.response.OutputResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -24,12 +27,23 @@ public class IRSRoundController { @Autowired private IRSRoundService irsRoundService; + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserService userService; + @PostMapping(value = "/add") - public ResponseEntity> addRound(@RequestBody IRSRoundListDTO dto) { + public ResponseEntity> addRound(@RequestBody IRSRoundListDTO dto,@RequestHeader("jwtToken") String token) { Map response = new LinkedHashMap<>(); try { if (dto.getRounds().size() != 0) { - List s = irsRoundService.addRounds(dto.getRounds()); + if(token==null){ + response.put("statusCode", 401); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response) ; + } + Integer userId = jwtUtil.extractUserId(token); + List s = irsRoundService.addRounds(dto.getRounds(), userId, userService.getUserDetail(userId).getUserName()); if (s.size() != 0) { Map data = new HashMap<>(); data.put("entries", s); diff --git a/src/main/java/com/iemr/flw/controller/IncentiveController.java b/src/main/java/com/iemr/flw/controller/IncentiveController.java index 670d611be..fe1d93ac2 100644 --- a/src/main/java/com/iemr/flw/controller/IncentiveController.java +++ b/src/main/java/com/iemr/flw/controller/IncentiveController.java @@ -1,8 +1,7 @@ package com.iemr.flw.controller; import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.IncentiveActivityDTO; -import com.iemr.flw.dto.iemr.IncentiveRequestDTO; +import com.iemr.flw.dto.iemr.*; import com.iemr.flw.service.IncentiveService; import com.iemr.flw.utils.JwtUtil; import com.iemr.flw.utils.response.OutputResponse; @@ -13,10 +12,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.sql.Timestamp; +import java.util.HashMap; import java.util.List; +import java.util.Map; @RestController @RequestMapping(value = "/incentive", consumes = "application/json", produces = "application/json") @@ -28,9 +31,12 @@ public class IncentiveController { @Autowired IncentiveService incentiveService; + @Autowired + private JwtUtil jwtUtil; + @Operation(summary = "save incentive master") - @RequestMapping(value = { "/masterData/saveAll" }, method = { RequestMethod.POST }) - public String saveIncentiveMasterData(@RequestBody List activityDTOS,@RequestHeader(value = "Authorization") String authorization, HttpServletRequest request) { + @RequestMapping(value = {"/masterData/saveAll"}, method = {RequestMethod.POST}) + public String saveIncentiveMasterData(@RequestBody List activityDTOS, @RequestHeader(value = "Authorization") String authorization, HttpServletRequest request) { OutputResponse response = new OutputResponse(); try { logger.info("Saving All incentives"); @@ -50,9 +56,9 @@ public String saveIncentiveMasterData(@RequestBody List ac } @Operation(summary = "get incentive master") - @RequestMapping(value = { "/masterData/getAll" }, method = { RequestMethod.POST }) + @RequestMapping(value = {"/masterData/getAll"}, method = {RequestMethod.POST}) public String saveIncentiveMasterData(@RequestBody IncentiveRequestDTO incentiveRequestDTO, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "Authorization") String Authorization) { OutputResponse response = new OutputResponse(); try { @@ -61,7 +67,7 @@ public String saveIncentiveMasterData(@RequestBody IncentiveRequestDTO incentive // add logic for different state or district if (incentiveRequestDTO != null) { String s = incentiveService.getIncentiveMaster(incentiveRequestDTO); - logger.info("All incentives"+s); + // logger.info("All incentives" + s); if (s != null) response.setResponse(s); @@ -77,21 +83,44 @@ public String saveIncentiveMasterData(@RequestBody IncentiveRequestDTO incentive } + @Operation(summary = "get high risk assessment data of all beneficiaries registered with given user id") + @RequestMapping(value = {"/fetchUserData"}, method = {RequestMethod.POST}) + public String getAllIncentivesByUserId(@RequestBody GetBenRequestHandler requestDTO, + @RequestHeader(value = "Authorization") String Authorization) { + OutputResponse response = new OutputResponse(); + try { + if (requestDTO != null) { + logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + String s = incentiveService.getAllIncentivesByUserId(requestDTO); + //logger.info("User Incentive:" + s); + if (s != null) + response.setResponse(s); + else + response.setError(5000, "No record found"); + } else + response.setError(5000, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in high risk assessment data : " + e); + response.setError(5000, "Error in high risk assessment data : " + e); + } + return response.toString(); + } @Operation(summary = "get high risk assessment data of all beneficiaries registered with given user id") - @RequestMapping(value = { "/fetchUserData" }, method = { RequestMethod.POST }) - public String getAllIncentivesByUserId(@RequestBody GetBenRequestHandler requestDTO, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestMapping(value = {"/claimedIncentiveByUser"}, method = {RequestMethod.POST}) + public String getAllIncentivesByUserIdGroupByCount(@RequestBody GetBenRequestHandler requestDTO, + @RequestHeader(value = "Authorization") String Authorization) { OutputResponse response = new OutputResponse(); try { if (requestDTO != null) { logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + requestDTO); - String s = incentiveService.getAllIncentivesByUserId(requestDTO); - logger.info("User Incentive:"+s); + String s = incentiveService.getAllIncentivesGroupedSummary(requestDTO); + logger.info("User Incentive:" + s); if (s != null) response.setResponse(s); else @@ -105,4 +134,86 @@ public String getAllIncentivesByUserId(@RequestBody GetBenRequestHandler request return response.toString(); } + @Operation(summary = "get high risk assessment data of all beneficiaries registered with given user id") + @RequestMapping(value = {"/AllIncentiveByActivityId"}, method = {RequestMethod.POST}) + public String getAllIncentivesByActivityIdAndUser(@RequestBody GetBenRequestHandler requestDTO, + @RequestHeader(value = "Authorization") String Authorization) { + OutputResponse response = new OutputResponse(); + try { + + if (requestDTO != null) { + logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + String s = incentiveService.getAllIncentivesGroupedActivity(requestDTO); + logger.info("User Incentive:" + s); + if (s != null) + response.setResponse(s); + else + response.setError(5000, "No record found"); + } else + response.setError(5000, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in high risk assessment data : " + e); + response.setError(5000, "Error in high risk assessment data : " + e); + } + return response.toString(); + } + + @RequestMapping(value = {"/update"}, method = RequestMethod.POST, consumes = {"multipart/form-data"}) + public String updateIncentive(@ModelAttribute PendingActivityDTO requestDTO) { + OutputResponse response = new OutputResponse(); + try { + + if (requestDTO != null) { + logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + String s = incentiveService.updateIncentive(requestDTO); + logger.info("User Incentive:" + s); + if (s != null) + response.setResponse(s); + else + response.setError(500, "No record found"); + } else + response.setError(500, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in high risk assessment data : " + e); + response.setError(500, "Error in high risk assessment data : " + e); + } + return response.toString(); + + + } + + @PostMapping("/updateClaim") + public ResponseEntity updateApprovalStatus( + @RequestBody UpdateClaimedStatusRequestDTO request, + @RequestHeader(value = "JwtToken") String token) { + + try { + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("UNAUTHORIZED"); + } + + String result = incentiveService.updateClaimStatus( + jwtUtil.extractUserId(token), + request.getMonth(), + request.getYear(), + request.isClaimed(), + token + ); + + Map response = new HashMap<>(); + response.put("statusCode", 200); + response.put("message", result); + + return ResponseEntity.ok(response); + + } catch (Exception e) { + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Server error: " + e.getMessage()); + } + } + + } diff --git a/src/main/java/com/iemr/flw/controller/MaaMeetingController.java b/src/main/java/com/iemr/flw/controller/MaaMeetingController.java index d9bcdb1b2..012438c56 100644 --- a/src/main/java/com/iemr/flw/controller/MaaMeetingController.java +++ b/src/main/java/com/iemr/flw/controller/MaaMeetingController.java @@ -35,22 +35,102 @@ public MaaMeetingController(MaaMeetingService service) { @PostMapping(value = "/saveAll", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity saveMeeting( + + @RequestPart(value = "villageName", required = false) String villageName, + @RequestPart(value = "noOfPragnentWoment", required = false) String noOfPragnentWomen, + @RequestPart(value = "noOfLactingMother", required = false) String noOfLactingMother, + @RequestPart(value = "mitaninActivityCheckList", required = false) String mitaninActivityCheckList, + @RequestPart(value = "meetingDate") String meetingDate, + @RequestPart(value = "place", required = false) String place, + @RequestPart(value = "participants") String participants, + @RequestPart(value = "ashaId", required = false) String ashaId, + @RequestPart(value = "createdBy", required = false) String createdBy, + @RequestPart(value = "meetingImages", required = false) List meetingImages + ) { + try { + MaaMeetingRequestDTO dto = new MaaMeetingRequestDTO(); + + if (meetingDate != null && !meetingDate.isEmpty()) { + dto.setMeetingDate(LocalDate.parse(meetingDate)); + } + + dto.setPlace(place); + dto.setVillageName(villageName); + dto.setMitaninActivityCheckList(mitaninActivityCheckList); + dto.setCreatedBY(createdBy); + + if (participants != null && !participants.isEmpty()) { + dto.setParticipants(Integer.parseInt(participants)); + } + + if (ashaId != null && !ashaId.isEmpty()) { + dto.setAshaId(Integer.parseInt(ashaId)); + } + + if (noOfLactingMother != null && !noOfLactingMother.isEmpty()) { + dto.setNoOfLactingMother(Integer.parseInt(noOfLactingMother)); + } + + if (noOfPragnentWomen != null && !noOfPragnentWomen.isEmpty()) { + dto.setNoOfPragnentWomen(Integer.parseInt(noOfPragnentWomen)); + } + + if (meetingImages != null && !meetingImages.isEmpty()) { + dto.setMeetingImages(meetingImages.toArray(new MultipartFile[0])); + } + + service.saveMeeting(dto); + + return ResponseEntity.ok("Saved Successfully"); + + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.badRequest().body(e.getMessage()); + } + } + + @PostMapping(value = "/update", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity updateMeeting( @RequestPart("meetingDate") String meetingDate, @RequestPart("place") String place, @RequestPart("participants") String participants, + @RequestPart("id") Long meetingId, @RequestPart("ashaId") String ashaId, @RequestPart("createdBy") String createdBy, @RequestPart(value = "meetingImages", required = false) List meetingImages) { try { MaaMeetingRequestDTO dto = new MaaMeetingRequestDTO(); - dto.setMeetingDate(LocalDate.parse(meetingDate)); - dto.setPlace(place); - dto.setParticipants(Integer.parseInt(participants)); - dto.setAshaId(Integer.parseInt(ashaId)); - dto.setCreatedBY(createdBy); - dto.setMeetingImages(meetingImages != null ? meetingImages.toArray(new MultipartFile[0]) : null); + if (meetingDate != null) { + dto.setMeetingDate(LocalDate.parse(meetingDate)); - service.saveMeeting(dto); + } + if (place != null) { + dto.setPlace(place); + + } + if (participants != null) { + dto.setParticipants(Integer.parseInt(participants)); + + } + if (ashaId != null) { + dto.setAshaId(Integer.parseInt(ashaId)); + + } + if (createdBy != null) { + dto.setCreatedBY(createdBy); + + } + if (meetingImages != null) { + dto.setMeetingImages(meetingImages != null ? meetingImages.toArray(new MultipartFile[0]) : null); + + } + if(meetingId!=null){ + dto.setId(meetingId); + } + if (dto != null) { + service.updateMeeting(dto); + + } return ResponseEntity.ok("Saved Successfully"); } catch (Exception e) { return ResponseEntity.badRequest().body(e.getMessage()); diff --git a/src/main/java/com/iemr/flw/controller/MalariaFollowUpController.java b/src/main/java/com/iemr/flw/controller/MalariaFollowUpController.java index 4e3ae1942..29204ab63 100644 --- a/src/main/java/com/iemr/flw/controller/MalariaFollowUpController.java +++ b/src/main/java/com/iemr/flw/controller/MalariaFollowUpController.java @@ -28,6 +28,9 @@ import com.iemr.flw.dto.iemr.MalariaFollowListUpDTO; import com.iemr.flw.dto.iemr.MalariaFollowUpDTO; import com.iemr.flw.service.MalariaFollowUpService; +import com.iemr.flw.utils.JwtUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -39,46 +42,59 @@ @RestController @RequestMapping(value = "/follow-up", headers = "Authorization") public class MalariaFollowUpController { + private final Logger logger = LoggerFactory.getLogger(MalariaFollowUpController.class); + + @Autowired + private JwtUtil jwtUtil; @Autowired private MalariaFollowUpService followUpService; @RequestMapping(value = "save", method = RequestMethod.POST) - public ResponseEntity> save(@RequestBody MalariaFollowUpDTO dto) { + public ResponseEntity> save(@RequestBody MalariaFollowUpDTO dto,@RequestHeader(value = "JwtToken") String token) { Map response = new HashMap<>(); try { - Boolean result = followUpService.saveFollowUp(dto); - if (result) { - response.put("status", "Success"); - response.put("statusCode", 200); - response.put("message", "Follow-up saved successfully"); - } else { - response.put("status", "Failed"); - response.put("statusCode", 400); + if(token!=null){ + + Boolean result = followUpService.saveFollowUp(dto,token); + if (result) { + response.put("status", "Success"); + response.put("statusCode", 200); + response.put("message", "Follow-up saved successfully"); + } else { + response.put("status", "Failed"); + response.put("statusCode", 5000); + } } + } catch (Exception e) { response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); } @RequestMapping(value = "get", method = RequestMethod.POST) - public ResponseEntity> getFollowUpsByUserId(@RequestBody GetDiseaseRequestHandler getDiseaseRequestHandler) { + public ResponseEntity> getFollowUpsByUserId(@RequestBody GetDiseaseRequestHandler getDiseaseRequestHandler,@RequestHeader(value = "JwtToken") String token) { Map response = new HashMap<>(); try { - List data = followUpService.getByUserId(getDiseaseRequestHandler.getUserId()); - response.put("status", "Success"); - response.put("statusCode", 200); - response.put("data", data); - if (data.isEmpty()) { - response.put("message", "No records found"); + if(token!=null){ + List data = followUpService.getByUserId(jwtUtil.extractUserId(token)); + response.put("status", "Success"); + response.put("statusCode", 200); + response.put("data", data); + if (data.isEmpty()) { + response.put("message", "No records found"); + } } + } catch (Exception e) { + logger.info("Fail Malaria followUp: "+e.getMessage()); + logger.info("Fail Malaria full error: "+e); response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); diff --git a/src/main/java/com/iemr/flw/controller/MaternalHealthController.java b/src/main/java/com/iemr/flw/controller/MaternalHealthController.java index e23cc8ed4..9c8459daa 100644 --- a/src/main/java/com/iemr/flw/controller/MaternalHealthController.java +++ b/src/main/java/com/iemr/flw/controller/MaternalHealthController.java @@ -15,17 +15,18 @@ import io.swagger.v3.oas.annotations.Operation; import jakarta.servlet.http.HttpServletRequest; -import org.checkerframework.checker.units.qual.A; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.sql.Timestamp; import java.util.List; @RestController -@RequestMapping(value = "/maternalCare", headers = "Authorization", consumes = "application/json", produces = "application/json") +@RequestMapping(value = "/maternalCare", consumes = "application/json", produces = "application/json") public class MaternalHealthController { private final Logger logger = LoggerFactory.getLogger(CoupleController.class); @@ -91,21 +92,26 @@ public String getPregnantWomanList(@RequestBody GetBenRequestHandler requestDTO, response.setError(5000, "Error in pregnant woman get data : " + e); } return response.toString(); + } @Operation(summary = "save anc visit details") @RequestMapping(value = { "/ancVisit/saveAll" }, method = { RequestMethod.POST }) public String saveANCVisit(@RequestBody List ancVisitDTOs, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "JwtToken") String token) { OutputResponse response = new OutputResponse(); try { if (ancVisitDTOs.size() != 0) { logger.info("Saving ANC visits with timestamp : " + new Timestamp(System.currentTimeMillis())); - String s = maternalHealthService.saveANCVisit(ancVisitDTOs); - if (s != null) - response.setResponse(s); - else - response.setError(5000, "Saving anc data to db failed"); + if(token!=null){ + String s = maternalHealthService.saveANCVisit(ancVisitDTOs,jwtUtil.extractUserId(token)); + + if (s != null) + response.setResponse(s); + else + response.setError(5000, "Saving anc data to db failed"); + } + } else response.setError(5000, "Invalid/NULL request obj"); } catch (Exception e) { @@ -141,6 +147,67 @@ public String getANCVisitDetails(@RequestBody GetBenRequestHandler requestDTO, return response.toString(); } + @Operation(summary = "save anc visit question") + @RequestMapping(value = { "/ancVisit/counselling/saveAll" }, method = { RequestMethod.POST }) + public String saveANCVisitQuestion(@RequestBody List ancVisitQuestionsDTOS, + @RequestHeader(value = "JwtToken") String Authorization) { + OutputResponse response = new OutputResponse(); + try { + if (ancVisitQuestionsDTOS.size() != 0) { + + logger.info("Saving ANC visits with timestamp : " + new Timestamp(System.currentTimeMillis())); + String s = maternalHealthService.saveANCVisitQuestions(ancVisitQuestionsDTOS,Authorization); + if (s != null) + response.setResponse(s); + else + response.setError(500, "Saving anc data to db failed"); + } else + response.setError(500, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in save ANC visit details : ",e); + + response.setError(500, "Error in save ANC visit details : " + e); + } + return response.toString(); + } + + @Operation(summary = "get anc visit questions") + @RequestMapping(value = { "/ancVisit/counselling/getAll" }, method = { RequestMethod.POST }) + public ResponseEntity>> getANCVisitQuestion(@RequestBody GetBenRequestHandler requestDTO, + @RequestHeader(value = "JwtToken") String Authorization) { + StandardResponse> response = new StandardResponse<>(); + + try { + if (requestDTO != null) { + logger.info("Request: " + requestDTO); + + List result = maternalHealthService.getANCCounselling(requestDTO); + + response.setStatusCode(200); + response.setStatus("Success"); + response.setErrorMessage("Success"); + response.setData(result); + + return ResponseEntity.ok(response); + + } else { + response.setStatusCode(400); + response.setStatus("Failed"); + response.setErrorMessage("Invalid request object"); + response.setData(null); + return ResponseEntity.badRequest().body(response); + } + } catch (Exception e) { + logger.error("Exception in fetching HBNC visits", e); + + response.setStatusCode(500); + response.setStatus("Failed"); + response.setErrorMessage("Internal Server Error: " + e.getMessage()); + response.setData(null); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + @Operation(summary = "save Delivery Outcome details") @RequestMapping(value = { "/deliveryOutcome/saveAll" }, method = { RequestMethod.POST }) public String saveDeliveryOutcome(@RequestBody List deliveryOutcomeDTOS, @@ -163,6 +230,7 @@ public String saveDeliveryOutcome(@RequestBody List delivery response.setError(5000, "Error in save delivery outcome details : " + e); } return response.toString(); + } @Operation(summary = "get Delivery Outcome details") @@ -177,9 +245,9 @@ public String getDeliveryOutcome(@RequestBody GetBenRequestHandler requestDTO, List result = deliveryOutcomeService.getDeliveryOutcome(requestDTO); Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); String s = gson.toJson(result); - if (s != null) - response.setResponse(s); - else + if (result != null && !result.isEmpty()) { + response.setResponse(gson.toJson(result)); + }else response.setError(5000, "No record found"); } else response.setError(5000, "Invalid/NULL request obj"); diff --git a/src/main/java/com/iemr/flw/controller/TBController.java b/src/main/java/com/iemr/flw/controller/TBController.java index 6beb9008e..e95c3ab4c 100644 --- a/src/main/java/com/iemr/flw/controller/TBController.java +++ b/src/main/java/com/iemr/flw/controller/TBController.java @@ -1,14 +1,18 @@ package com.iemr.flw.controller; +import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.TBConfirmedRequestDTO; import com.iemr.flw.dto.iemr.TBScreeningRequestDTO; import com.iemr.flw.dto.iemr.TBSuspectedRequestDTO; +import com.iemr.flw.service.TBConfirmedCaseService; import com.iemr.flw.service.TBScreeningService; import com.iemr.flw.service.TBSuspectedService; import com.iemr.flw.utils.response.OutputResponse; import io.swagger.v3.oas.annotations.Operation; +import org.checkerframework.checker.units.qual.A; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +32,9 @@ public class TBController { @Autowired private TBSuspectedService tbSuspectedService; + @Autowired + private TBConfirmedCaseService tbConfirmedCaseService; + @Operation(summary = "get tb screening data of all beneficiaries registered with given user id") @RequestMapping(value = { "/screening/getAll" }, method = { RequestMethod.POST }) public String getAllScreeningByUserId(@RequestBody GetBenRequestHandler requestDTO, @@ -42,9 +49,9 @@ public String getAllScreeningByUserId(@RequestBody GetBenRequestHandler requestD if (s != null) response.setResponse(s); else - response.setError(5000, "No record found"); + response.setError(500, "No record found"); } else - response.setError(5000, "Invalid/NULL request obj"); + response.setError(500, "Invalid/NULL request obj"); } catch (Exception e) { logger.error("Error in tb screening get data : " + e); response.setError(5000, "Error in tb screening get data : " + e); @@ -66,9 +73,9 @@ public String saveAllScreeningByUserId(@RequestBody TBScreeningRequestDTO reques if (s != null) response.setResponse(s); else - response.setError(5000, "No record found"); + response.setError(500, "No record found"); } else - response.setError(5000, "Invalid/NULL request obj"); + response.setError(500, "Invalid/NULL request obj"); } catch (Exception e) { logger.error("Error in save tb screening details : " + e); response.setError(5000, "Error in save tb suspected details : " + e); @@ -91,12 +98,12 @@ public String getAllSuspectedByUserId(@RequestBody GetBenRequestHandler requestD if (s != null) response.setResponse(s); else - response.setError(5000, "No record found"); + response.setError(500, "No record found"); } else - response.setError(5000, "Invalid/NULL request obj"); + response.setError(500, "Invalid/NULL request obj"); } catch (Exception e) { logger.error("Error in get data : " + e); - response.setError(5000, "Error in get data : " + e); + response.setError(500, "Error in get data : " + e); } return response.toString(); } @@ -115,13 +122,73 @@ public String saveAllSuspectedByUserId(@RequestBody TBSuspectedRequestDTO reques if (s != null) response.setResponse(s); else - response.setError(5000, "No record found"); + response.setError(500, "No record found"); } else - response.setError(5000, "Invalid/NULL request obj"); + response.setError(500, "Invalid/NULL request obj"); } catch (Exception e) { logger.error("Error in save tb suspected details : " + e); response.setError(5000, "Error in save tb suspected details : " + e); } return response.toString(); } + + @Operation(summary = "save tb confirmed case data of beneficiary") + @RequestMapping(value = { "/confirmed/save" }, method = { RequestMethod.POST }) + public String saveConfirmedCase( + @RequestBody TBConfirmedRequestDTO requestDTO, + @RequestHeader(value = "jwtToken") String token) { + + OutputResponse response = new OutputResponse(); + + try { + if (requestDTO != null) { + + logger.info("request object with timestamp : " + + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + + String result = tbConfirmedCaseService.save(requestDTO.getTbConfirmedList(), token); + + if (result != null) + response.setResponse(result); + else + response.setError(500, "No record saved"); + + } else { + response.setError(500, "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in save tb confirmed case details : ", e); + response.setError(500, "Error in save tb confirmed case details : " + e.getMessage()); + } + + return response.toString(); + } + + @Operation(summary = "get tb confirmed case by beneficiary id") + @RequestMapping(value = { "/confirmed/getAll" }, method = { RequestMethod.GET }) + public String getConfirmedByBenId( + @RequestHeader(value = "jwtToken") String token) { + + OutputResponse response = new OutputResponse(); + + try { + String result = + tbConfirmedCaseService.getByUserId(token); + + if (result != null) + response.setResponse(result); + else + response.setError(404, "No record found"); + + } catch (Exception e) { + logger.error("Error in get tb confirmed case details : ", e); + response.setError(500, "Error in get tb confirmed case details : " + e.getMessage()); + } + + return response.toString(); + } + + + } diff --git a/src/main/java/com/iemr/flw/controller/UwinSessionController.java b/src/main/java/com/iemr/flw/controller/UwinSessionController.java index 6fd31b160..6a273d9ab 100644 --- a/src/main/java/com/iemr/flw/controller/UwinSessionController.java +++ b/src/main/java/com/iemr/flw/controller/UwinSessionController.java @@ -31,14 +31,14 @@ public class UwinSessionController { @Autowired private JwtUtil jwtUtil; - @RequestMapping(value = "saveAll", method = RequestMethod.POST, headers = "Authorization", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @RequestMapping(value = "saveAll", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity saveSession( @RequestPart("meetingDate") String meetingDate, @RequestPart("place") String place, @RequestPart("participants") String participants, @RequestPart("ashaId") String ashaId, @RequestPart("createdBy") String createdBy, - @RequestPart(value = "meetingImages", required = false) List images) throws Exception { + @RequestPart(value = "meetingImages", required = false) List images,@RequestHeader(value = "jwtToken") String jwtToken) throws Exception { Map response = new LinkedHashMap<>(); UwinSessionRequestDTO dto = new UwinSessionRequestDTO(); diff --git a/src/main/java/com/iemr/flw/controller/VillageLevelFormController.java b/src/main/java/com/iemr/flw/controller/VillageLevelFormController.java index ddbb7a76b..884f794d1 100644 --- a/src/main/java/com/iemr/flw/controller/VillageLevelFormController.java +++ b/src/main/java/com/iemr/flw/controller/VillageLevelFormController.java @@ -36,13 +36,13 @@ import java.util.Map; @RestController -@RequestMapping(value = "/forms/villageLevel", headers = "Authorization") +@RequestMapping(value = "/forms/villageLevel") public class VillageLevelFormController { @Autowired private VillageLevelFormService villageLevelFormService; - @RequestMapping(value = "vhnd/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "vhnd/saveAll",method = RequestMethod.POST) public ResponseEntity> saveVhndForm(@RequestBody VhndDto dto) { Map response = new HashMap<>(); if (!dto.getEntries().isEmpty()) { @@ -64,7 +64,7 @@ public ResponseEntity> saveVhndForm(@RequestBody VhndDto dto } - @RequestMapping(value = "vhnc/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "vhnc/saveAll", method = RequestMethod.POST) public ResponseEntity> saveVhncForm(@RequestBody VhncDto dto) { Map response = new HashMap<>(); @@ -87,7 +87,7 @@ public ResponseEntity> saveVhncForm(@RequestBody VhncDto dto } - @RequestMapping(value = "phc/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "phc/saveAll", method = RequestMethod.POST) public ResponseEntity> savePhcForm(@RequestBody PhcReviewMeetingDTO dto) { Map response = new HashMap<>(); @@ -109,7 +109,7 @@ public ResponseEntity> savePhcForm(@RequestBody PhcReviewMee } - @RequestMapping(value = "ahd/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "ahd/saveAll", method = RequestMethod.POST) public ResponseEntity> saveAhdForm(@RequestBody AhdMeetingDto dto) { Map response = new HashMap<>(); @@ -129,7 +129,7 @@ public ResponseEntity> saveAhdForm(@RequestBody AhdMeetingDt } - @RequestMapping(value = "deworming/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "deworming/saveAll", method = RequestMethod.POST) public ResponseEntity> saveDewormingForm(@RequestBody DewormingDto dto) { Map response = new HashMap<>(); @@ -150,7 +150,7 @@ public ResponseEntity> saveDewormingForm(@RequestBody Deworm } - @RequestMapping(value = "getAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "getAll", method = RequestMethod.POST) public ResponseEntity> getVillageLevelFormData(@RequestBody GetVillageLevelRequestHandler getVillageLevelRequestHandler) { Map response = new LinkedHashMap<>(); diff --git a/src/main/java/com/iemr/flw/controller/health/HealthController.java b/src/main/java/com/iemr/flw/controller/health/HealthController.java new file mode 100644 index 000000000..933085544 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/health/HealthController.java @@ -0,0 +1,83 @@ +/* +* 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.controller.health; + +import java.time.Instant; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.iemr.flw.service.health.HealthService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +@RestController +@RequestMapping("/health") +@Tag(name = "Health Check", description = "APIs for checking infrastructure health status") +public class HealthController { + + private static final Logger logger = LoggerFactory.getLogger(HealthController.class); + + private final HealthService healthService; + + public HealthController(HealthService healthService) { + this.healthService = healthService; + } + + @GetMapping + @Operation(summary = "Check infrastructure health", + description = "Returns the health status of MySQL, Redis, and other configured services") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "Services are UP or DEGRADED (operational with warnings)"), + @ApiResponse(responseCode = "503", description = "One or more critical services are DOWN") + }) + public ResponseEntity> checkHealth() { + logger.debug("Health check endpoint called"); + + try { + Map healthStatus = healthService.checkHealth(); + String overallStatus = (String) healthStatus.get("status"); + + HttpStatus httpStatus = "DOWN".equals(overallStatus) ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.OK; + + logger.debug("Health check completed with status: {}", overallStatus); + return new ResponseEntity<>(healthStatus, httpStatus); + + } catch (Exception e) { + logger.error("Unexpected error during health check", e); + + Map errorResponse = Map.of( + "status", "DOWN", + "timestamp", Instant.now().toString() + ); + + return new ResponseEntity<>(errorResponse, HttpStatus.SERVICE_UNAVAILABLE); + } + } +} diff --git a/src/main/java/com/iemr/flw/controller/version/VersionController.java b/src/main/java/com/iemr/flw/controller/version/VersionController.java new file mode 100644 index 000000000..f2f2bf66f --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/version/VersionController.java @@ -0,0 +1,80 @@ +/* +* 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.controller.version; + +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; + +@RestController +public class VersionController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + + private static final String UNKNOWN_VALUE = "unknown"; + + @Operation(summary = "Get version information") + @GetMapping(value = "/version", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> versionInformation() { + Map response = new LinkedHashMap<>(); + try { + logger.info("version Controller Start"); + Properties gitProperties = loadGitProperties(); + response.put("buildTimestamp", gitProperties.getProperty("git.build.time", UNKNOWN_VALUE)); + response.put("version", gitProperties.getProperty("git.build.version", UNKNOWN_VALUE)); + response.put("branch", gitProperties.getProperty("git.branch", UNKNOWN_VALUE)); + response.put("commitHash", gitProperties.getProperty("git.commit.id.abbrev", UNKNOWN_VALUE)); + } catch (Exception e) { + logger.error("Failed to load version information", e); + response.put("buildTimestamp", UNKNOWN_VALUE); + response.put("version", UNKNOWN_VALUE); + response.put("branch", UNKNOWN_VALUE); + response.put("commitHash", UNKNOWN_VALUE); + } + logger.info("version Controller End"); + return ResponseEntity.ok(response); + } + + private Properties loadGitProperties() throws IOException { + Properties properties = new Properties(); + try (InputStream input = getClass().getClassLoader() + .getResourceAsStream("git.properties")) { + if (input != null) { + properties.load(input); + } + } + return properties; + } +} 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 ac336da13..297694b7c 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java @@ -386,6 +386,9 @@ public class RMNCHBeneficiaryDetailsRmnch { @Expose private Integer noofAlivechildren; + @Expose + private Boolean isDeactivate; + @Expose @Transient private Integer servicePointID; 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 9ab4f822b..3a3ccec86 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java @@ -325,4 +325,8 @@ public class RMNCHHouseHoldDetails { @Column(name = "mohallaName") private String mohallaName; + @Expose + @Column(name = "isDeactivate") + private Boolean isDeactivate; + } diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java index 72e994f5b..779a09da4 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java @@ -186,4 +186,8 @@ public class RMNCHMBeneficiarydetail { @Transient private Integer ProviderServiceMapID; + @Expose + @Column(name = "familyid") + private String familyId; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java b/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java index c5240d1c3..4128f0826 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java @@ -167,6 +167,12 @@ public class ANCVisit { @Column(name = "date_of_sterilisation") private Timestamp dateSterilisation; + @Column (name = "place_of_anc") + private String placeOfAnc; + + @Column(name = "place_of_ancId") + private Integer placeOfAncId; + diff --git a/src/main/java/com/iemr/flw/domain/iemr/AbhaApiResponse.java b/src/main/java/com/iemr/flw/domain/iemr/AbhaApiResponse.java new file mode 100644 index 000000000..db38d11ad --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/AbhaApiResponse.java @@ -0,0 +1,21 @@ +package com.iemr.flw.domain.iemr; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; +import lombok.Data; + +import java.util.List; + +@Data +public class AbhaApiResponse { + + @JsonProperty("status_code") + private String statusCode; + + private String message; + + @JsonProperty("data") + @JsonAlias("object_data") + private List data; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java new file mode 100644 index 000000000..46737f12a --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java @@ -0,0 +1,128 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "anc_counselling_care", schema = "db_iemr") +@Data +public class AncCounsellingCare { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "beneficiary_id", nullable = false) + private Long beneficiaryId; + + @Column(name = "visit_date") + private LocalDate visitDate; + + @Column(name = "home_visit_date", nullable = false) + private LocalDate homeVisitDate; + + @Column(name = "anc_visit_id", nullable = false) + private Long ancVisitId; + + @Column(name = "user_id") + private Integer userId; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "updated_by") + private String updatedBy; + + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + /* ---------- BOOLEAN FLAGS ---------- */ + + @Column(name = "select_all") + private Boolean selectAll = false; + + @Column(name = "swelling") + private Boolean swelling = false; + + @Column(name = "high_bp") + private Boolean highBp = false; + + @Column(name = "convulsions") + private Boolean convulsions = false; + + @Column(name = "anemia") + private Boolean anemia = false; + + @Column(name = "reduced_fetal_movement") + private Boolean reducedFetalMovement = false; + + @Column(name = "age_risk") + private Boolean ageRisk = false; + + @Column(name = "child_gap") + private Boolean childGap = false; + + @Column(name = "short_height") + private Boolean shortHeight = false; + + @Column(name = "pre_preg_weight") + private Boolean prePregWeight = false; + + @Column(name = "bleeding") + private Boolean bleeding = false; + + @Column(name = "miscarriage_history") + private Boolean miscarriageHistory = false; + + @Column(name = "four_plus_delivery") + private Boolean fourPlusDelivery = false; + + @Column(name = "first_delivery") + private Boolean firstDelivery = false; + + @Column(name = "twin_pregnancy") + private Boolean twinPregnancy = false; + + @Column(name = "c_section_history") + private Boolean cSectionHistory = false; + + @Column(name = "pre_existing_disease") + private Boolean preExistingDisease = false; + + @Column(name = "fever_malaria") + private Boolean feverMalaria = false; + + @Column(name = "jaundice") + private Boolean jaundice = false; + + @Column(name = "sickle_cell") + private Boolean sickleCell = false; + + @Column(name = "prolonged_labor") + private Boolean prolongedLabor = false; + + @Column(name = "malpresentation") + private Boolean malpresentation = false; + + /* ---------- Lifecycle Hooks ---------- */ + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } + + /* ---------- Getters & Setters ---------- */ + // Lombok use kar raha ho toh @Getter @Setter laga sakta hai +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java b/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java new file mode 100644 index 000000000..ee641db8b --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java @@ -0,0 +1,34 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "asha_supervisor_mapping") +@Data +@NoArgsConstructor +public class AshaSupervisorMapping { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "supervisorUserID") + private Integer supervisorUserID; + + @Column(name = "ashaUserID") + private Integer ashaUserID; + + @Column(name = "facilityID") + private Integer facilityID; + + @Column(name = "deleted", insertable = false, updatable = true) + private Boolean deleted; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java b/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java index 36fba04ec..2df2bf43c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java @@ -27,7 +27,7 @@ public class AshaWorker { private Integer employeeId; // Changed from Integer to String @Column(name = "dob") - private LocalDate dob; // Changed from String to LocalDate + private String dob; // Changed from String to LocalDate @Column(name = "mobile_number") @@ -40,7 +40,7 @@ public class AshaWorker { private String fatherOrSpouseName; @Column(name = "date_of_joining") - private LocalDate dateOfJoining; // Changed from String to LocalDate + private String dateOfJoining; // Changed from String to LocalDate @Column(name = "bank_account") @@ -98,8 +98,9 @@ public class AshaWorker { @Column(name = "ProviderServiceMapID") private Integer ProviderServiceMapID; + @Lob @Column(name = "profileImage") - private String profileImage; + private byte[] profileImage; @Column(name = "isFatherOrSpouse") private Boolean isFatherOrSpouse; diff --git a/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java b/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java new file mode 100644 index 000000000..e33e15439 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java @@ -0,0 +1,59 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "campaign_ors",schema = "db_iemr") +@Data +public class CampaignOrs { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "start_date", nullable = false) + private LocalDate startDate; + + @Column(name = "end_date", nullable = false) + private LocalDate endDate; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "number_of_families", nullable = false) + private Integer numberOfFamilies = 0; + + @Column(name = "campaign_photos",columnDefinition = "LONGTEXT") + private String campaignPhotos; + + @Column(name = "created_by", length = 200) + private String createdBy; + + @Column(name = "updated_by", length = 200) + private String updatedBy; + + @Column(name = "created_date", updatable = false) + private LocalDateTime createdDate; + + @Column(name = "updated_date") + private LocalDateTime updatedDate; + + /* ---------- Auto timestamps ---------- */ + + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.updatedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedDate = LocalDateTime.now(); + } + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java b/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java new file mode 100644 index 000000000..989ed1d1c --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java @@ -0,0 +1,330 @@ +/* +* 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.domain.iemr; + +import java.sql.Timestamp; + +import jakarta.persistence.*; + +import com.google.gson.annotations.Expose; +import lombok.Data; + +@Entity +@Table(name = "t_cbacdetails") +@Data +public class CbacDetailsImer { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Expose + @Column(name = "Id", insertable = false) + private Long id; + @Expose + @Column(name = "BeneficiaryRegId") + private Long beneficiaryRegId; + + @Expose + @Column(name = "Visitcode") + private Long visitCode; + @Expose + @Column(name = "Cbac_Age") + private String cbacAge; + @Expose + @Column(name = "Cbac_Age_Score") + private Integer cbacAgeScore; + @Expose + @Column(name = "Cbac_ConusmeGutka") + private String cbacConsumeGutka; + @Expose + @Column(name = "Cbac_ConusmeGutka_Score") + private Integer cbacConsumeGutkaScore; + @Expose + @Column(name = "cbac_alcohol") + private String cbacAlcohol; + @Expose + @Column(name = "cbac_alcohol_Score") + private Integer cbacAlcoholScore; + @Expose + @Column(name = "Cbac_waist_Male") + private String cbacWaistMale; + @Expose + @Column(name = "Cbac_waist_Male_Score") + private Integer cbacWaistMaleScore; + @Expose + @Column(name = "Cbac_Waist_Female") + private String cbacWaistFemale; + @Expose + @Column(name = "Cbac_Waist_Female_Score") + private Integer cbacWaistFemaleScore; + @Expose + @Column(name = "Cbac_PhysicalActivity") + private String cbacPhysicalActivity; + @Expose + @Column(name = "Cbac_PhysicalActivity_Score") + private Integer cbacPhysicalActivityScore; + @Expose + @Column(name = "Cbac_FamilyHistory_bpdiabetes") + private String cbacFamilyHistoryBpdiabetes; + @Expose + @Column(name = "Cbac_FamilyHistory_bpdiabetes_Score") + private Integer cbacFamilyHistoryBpdiabetesScore; + @Expose + @Column(name = "Cbac_ShortnessBreath") + private String cbacShortnessBreath; + @Expose + @Column(name = "Cbac_Cough2weeks") + private String cbacCough2weeks; + @Expose + @Column(name = "Cbac_Bloodsputum") + private String cbacBloodsputum; + @Expose + @Column(name = "Cbac_fever2weeks") + private String cbacFever2weeks; + @Expose + @Column(name = "Cbac_WeightLoss") + private String cbacWeightLoss; + @Expose + @Column(name = "Cbac_NightSweats") + private String cbacNightSweats; + @Expose + @Column(name = "Cbac_AntiTBDrugs") + private String cbacAntiTBDrugs; + @Expose + @Column(name = "Cabc_TB") + private String cbacTb; + @Expose + @Column(name = "Cbac_TBHistory") + private String cbacTBHistory; + @Expose + @Column(name = "Cbac_Ulceration") + private String cbacUlceration; + @Expose + @Column(name = "Cbac_RecurrentTingling") + private String cbacRecurrentTingling; + @Expose + @Column(name = "Cbac_FitsHistory") + private String cbacFitsHistory; + @Expose + @Column(name = "Cbac_MouthopeningDifficulty") + private String cbacMouthopeningDifficulty; + @Expose + @Column(name = "Cbac_MouthUlcers") + private String cbacMouthUlcers; + @Expose + @Column(name = "Cbac_MouthUlcersGrowth") + private String cbacMouthUlcersGrowth; + @Expose + @Column(name = "Cbac_Mouthredpatch") + private String cbacMouthredpatch; + @Expose + @Column(name = "Cbac_Painchewing") + private String cbacPainchewing; + @Expose + @Column(name = "Cbac_Tonechange") + private String cbacTonechange; + @Expose + @Column(name = "Cbac_Hypopigmentedpatches") + private String cbacHypopigmentedpatches; + @Expose + @Column(name = "Cbac_Thickenedskin") + private String cbacThickenedskin; + @Expose + @Column(name = "Cbac_Nodulesonskin") + private String cbacNodulesonskin; + @Expose + @Column(name = "Cbac_RecurrentNumbness") + private String cbacRecurrentNumbness; + @Expose + @Column(name = "Cbac_BlurredVision") + private String cbacBlurredVision; + @Expose + @Column(name = "Cbac_Difficultyreading") + private String cbacDifficultyreading; + @Expose + @Column(name = "Cbac_Painineyes") + private String cbacPainineyes; + @Expose + @Column(name = "Cbac_RednessPain") + private String cbacRednessPain; + @Expose + @Column(name = "Cbac_DifficultyHearing") + private String cbacDifficultyHearing; + @Expose + @Column(name = "Cbac_Clawingfingers") + private String cbacClawingfingers; + @Expose + @Column(name = "Cbac_HandTingling") + private String cbacHandTingling; + @Expose + @Column(name = "Cbac_InabilityCloseeyelid") + private String cbacInabilityCloseeyelid; + @Expose + @Column(name = "Cbac_DifficultHoldingObjects") + private String cbacDifficultHoldingObjects; + @Expose + @Column(name = "Cbac_Feetweakness") + private String cbacFeetweakness; + @Expose + @Column(name = "Cbac_LumpBreast") + private String cbacLumpBreast; + @Expose + @Column(name = "Cbac_BloodnippleDischarge") + private String cbacBloodnippleDischarge; + @Expose + @Column(name = "Cbac_Breastsizechange") + private String cbacBreastsizechange; + @Expose + @Column(name = "Cbac_BleedingPeriods") + private String cbacBleedingPeriods; + @Expose + @Column(name = "Cbac_BleedingMenopause") + private String cbacBleedingMenopause; + @Expose + @Column(name = "Cbac_BleedingIntercourse") + private String cbacBleedingIntercourse; + @Expose + @Column(name = "Cbac_VaginalDischarge") + private String cbacVaginalDischarge; + @Expose + @Column(name = "Cbac_FeelingUnsteady") + private String cbacFeelingUnsteady; + @Expose + @Column(name = "Cbac_PhysicalDisabilitySuffering") + private String cbacPhysicalDisabilitySuffering; + @Expose + @Column(name = "Cbac_NeedhelpEverydayActivities") + private String cbacNeedhelpEverydayActivities; + @Expose + @Column(name = "Cbac_Forgetnearones") + private String cbacForgetnearones; + @Expose + @Column(name = "ProviderServiceMapID") + private Integer providerServiceMapId; + + @Expose + @Column(name = "Total_Score") + private Integer totalScore; + @Expose + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + + @Expose + @Column(name = "Processed", insertable = false, updatable = true) + private Character processed; + + @Expose + @Column(name = "CreatedBy") + private String createdBy; + + @Expose + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + + @Expose + @Column(name = "ModifiedBy") + private String modifiedBy; + + @Expose + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; + + @Expose + @Column(name = "VanSerialNo") + private Integer vanSerialNo; + @Expose + @Column(name = "VanID") + private Integer vanId; + @Expose + @Column(name = "VehicalNo") + private String vehicalNo; + @Expose + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceId; + @Expose + @Column(name = "SyncedBy") + private String syncedBy; + @Expose + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Transient + @Expose + private Long beneficiaryId; + + @Expose + @Column(name = "Cbac_OccupationalExposure") + private String CbacOccupationalExposure; + + @Expose + @Column(name = "Cbac_BotheredProblem_last2weeks") + private String CbacBotheredProblemLast2weeks; + + @Expose + @Column(name = "Cbac_LittleInterest_Pleasure") + private String CbacLittleInterestPleasure; + + @Expose + @Column(name = "Cbac_Depressed_hopeless") + private String CbacDepressedhopeless; + + @Expose + @Column(name = "Cbac_DiscolorationSkin") + private String CbacDiscolorationSkin; + + @Expose + @Column(name = "Cbac_Cooking_Oil") + private String CbacCookingOil; + + @Expose + @Column(name = "Cbac_OccupationalExposure_score") + private String CbacOccupationalExposureScore; + + @Expose + @Column(name = "Cbac_BotheredProblem_last2weeks_score") + private String CbacBotheredProblemLast2weeksScore; + + @Expose + @Column(name = "Cbac_LittleInterest_Pleasure_score") + private String CbacLittleInterestPleasureScore; + + @Expose + @Column(name = "Cbac_Depressed_hopeless_score") + private String CbacDepressedhopelessScore; + + @Expose + @Column(name = "Cbac_Cooking_Oil_score") + private String CbacCookingOilScore; + + + @Expose + @Column(name = "Cbac_Feeling_Down_score") + private String CbacFeelingDownScore; + + @Expose + @Column(name = "is_refer") + private Boolean isRefer; + + + + + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/ChildVaccination.java b/src/main/java/com/iemr/flw/domain/iemr/ChildVaccination.java index 45d5562ee..4050b77c5 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ChildVaccination.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ChildVaccination.java @@ -10,6 +10,7 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import jakarta.persistence.Transient; +import org.checkerframework.checker.units.qual.C; @Entity @Table(name = "t_childvaccinedetail1", schema = "db_iemr", catalog = "") @@ -17,6 +18,8 @@ public class ChildVaccination { private long id; private Long beneficiaryRegId; private Long benVisitId; + + private Long ProviderServiceMapID; private String defaultReceivingAge; private Integer vaccineId; private String vaccineName; @@ -314,4 +317,14 @@ public String getReservedForChange() { public void setReservedForChange(String reservedForChange) { this.reservedForChange = reservedForChange; } + + @Basic + @Column(name = "ProviderServiceMapID") + public Long getProviderServiceMapID() { + return ProviderServiceMapID; + } + + public void setProviderServiceMapID(Long providerServiceMapID) { + ProviderServiceMapID = providerServiceMapID; + } } diff --git a/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java b/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java new file mode 100644 index 000000000..10689cff3 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java @@ -0,0 +1,75 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "cdtf_visit_details") +@Data +public class ChronicDiseaseVisitEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "beneficiary_id") + private Long benId; + + @Column(name = "household_id") + private Long hhId; + + @Column(name = "form_id") + private String formId; + + @Column(name = "version") + private Integer version; + + @Column(name = "visit_no") + private Integer visitNo; + + @Column(name = "follow_up_no") + private Integer followUpNo; + + @Column(name = "diagnosis_codes", columnDefinition = "TEXT") + private String diagnosisCodes; + + @Column(name = "treatment_start_date") + private LocalDate treatmentStartDate; + + @Column(name = "follow_up_date") + private LocalDate followUpDate; + + @Column(name = "form_data_json", columnDefinition = "JSON") + private String formDataJson; + + @Column(name = "user_id") + private Integer userID; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "created_date") + private LocalDateTime createdDate; + + @Column(name = "updated_by") + private Integer updatedBy; + + @Column(name = "updated_date") + private LocalDateTime updatedDate; + + // 🔹 Auto timestamps + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.updatedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedDate = LocalDateTime.now(); + } + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java b/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java index 6050fab57..d3a1b56ce 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java @@ -17,7 +17,6 @@ public class DeliveryOutcome { @Column(name = "ben_id") private Long benId; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MMM dd, yyyy, h:mm:ss a") @Column(name = "delivery_date") private Timestamp dateOfDelivery; @@ -54,7 +53,6 @@ public class DeliveryOutcome { @Column(name = "still_birth") private Integer stillBirth; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MMM dd, yyyy, h:mm:ss a") @Column(name = "discharge_date") private Timestamp dateOfDischarge; diff --git a/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java b/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java new file mode 100644 index 000000000..2f0c12ad1 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java @@ -0,0 +1,66 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "campaign_filariasis_mda",schema = "db_iemr") +@Data +public class FilariasisCampaign { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "start_date", nullable = false) + private LocalDate startDate; + + @Column(name = "end_date", nullable = false) + private LocalDate endDate; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "number_of_families", nullable = false) + private Integer numberOfFamilies = 0; + + @Column(name = "number_of_individuals", nullable = false) + private Integer numberOfIndividuals = 0; + + /** + * Store JSON array like ["img1.jpg","img2.jpg"] + * MySQL JSON column + */ + @Column(name = "mda_photos", columnDefinition = "json") + private String campaignPhotos; + + @Column(name = "created_by", length = 200) + private String createdBy; + + @Column(name = "updated_by", length = 200) + private String updatedBy; + + @Column(name = "created_date", updatable = false) + private LocalDateTime createdDate; + + @Column(name = "updated_date") + private LocalDateTime updatedDate; + + /* ---------- Auto timestamps ---------- */ + + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.updatedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedDate = LocalDateTime.now(); + } + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java b/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java index bcaeabc49..205716cc9 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java @@ -53,7 +53,7 @@ public class HbycChildVisit { private String other_place_of_death; @Column(name = "baby_weight") - private BigDecimal baby_weight; // 0.5 - 7.0 + private Integer baby_weight; // 0.5 - 7.0 @Column(name = "is_child_sick") private Boolean is_child_sick; diff --git a/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java b/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java index 0f078f5f1..6f3143e05 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java @@ -28,4 +28,10 @@ public class IRSRound { @Column(name = "householdId") private Long householdId; + @Column(name = "created_by") + private String createdBy; + + @Column(name = "user_id") + private Integer userId; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index b5c039f55..016f6271d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -36,7 +36,6 @@ public class IncentiveActivity { @Column(name = "group_name") private String group; - @Column(name = "fmr_code") private String fmrCode; @@ -59,4 +58,8 @@ public class IncentiveActivity { private Boolean isDeleted; + @Column(name = "state_activity_code") + private Integer stateActivityCode; + + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java index 5b921bb47..b6d193e63 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java @@ -3,6 +3,8 @@ import lombok.Data; import jakarta.persistence.*; + +import javax.management.MXBean; import java.sql.Timestamp; @Entity @@ -46,4 +48,43 @@ public class IncentiveActivityRecord { @Column(name = "updated_by") private String updatedBy; + + @Column(name = "is_eligible",columnDefinition = "tinyint(1) default 1") + private Boolean isEligible=true; + + @Column(name = "is_default_activity",columnDefinition = "tinyint(1) default 0") + private Boolean isDefaultActivity = false; + + @Column(name = "approval_status",columnDefinition = "int default 102") + Integer approvalStatus = 102; + + @Column(name = "verifiedBy_userId") + private Integer verifiedByUserId; + + @Column(name = "verifiedBy_userName") + private String verifiedByUserName; + + @Column(name = "reason") + private String reason; + + @Column(name = "other_reason") + private String otherReason; + + @Column(name = "is_claimed",columnDefinition = "tinyint(1) default 0") + private Boolean isClaimed = false; + + @Column(name = "approval_date") + private Timestamp approvalDate; + + @Column(name = "calimed_date") + private Timestamp calimedDate; + + @Transient + private String supervisorRole; + + @Transient + private String activityDec; + + @Transient + private String groupName; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java new file mode 100644 index 000000000..3f35dc599 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java @@ -0,0 +1,39 @@ +package com.iemr.flw.domain.iemr; + +import java.util.Date; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "incentive_pending_activity", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class IncentivePendingActivity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "activity_id", nullable = false) + private Long activityId; + + @Column(name = "record_id", nullable = false) + private Long recordId; + + @Column(name = "m_incentive_id") + private Long mincentiveId; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "created_date") + private Date createdDate; + + @Column(name = "updated_date") + private Date updatedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java b/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java index 2bfb29700..0e8437141 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java @@ -5,6 +5,7 @@ import java.sql.Timestamp; import java.time.LocalDate; +import java.util.List; @Entity @Data @@ -39,6 +40,18 @@ public class MaaMeeting { @Column(name = "meeting_images", columnDefinition = "LONGTEXT") private String meetingImagesJson; + @Column(name = "village_name") + private String villageName; + + @Column(name = "no_of_pragnent_women") + private Integer noOfPragnentWomen; + + @Column(name = "no_of_lacting_mother") + private Integer noOfLactingMother; + + @Column(name = "mitanin_activity_checkList") + private String mitaninActivityCheckList; + @Column(name = "created_by") private String createdBy; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java b/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java index 9444d1af6..1f57d23ae 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java @@ -9,21 +9,22 @@ @Data @Table(name = "i_mobilization_mosquito_net",schema = "db_iemr") public class MosquitoNetEntity { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "beneficiary_id") private Long beneficiaryId; + @Column(name = "household_id") private Long houseHoldId; + @Column(name = "visit_date") private LocalDate visitDate; @Column(name = "user_name") private String userName; - @Column(name = "user_id") private Integer userId; diff --git a/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java b/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java index 50ec33756..4dea0ce7c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java @@ -42,6 +42,19 @@ public class PHCReviewForm { @Column(name = "created_date", updatable = false) private Timestamp createdDate; + @Column(name = "village_name ") + private String villageName; + + @Column(name = "mitanin_history") + private String mitaninHistory; + + @Column(name = "mitanin_activity_checkList") + private String mitaninActivityCheckList; + + @Column(name = "place_Id") + private Integer placeId; + @Column(name = "form_type") private String formType; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java b/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java new file mode 100644 index 000000000..ddf7b8b60 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java @@ -0,0 +1,60 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "campaign_pulse_polio",schema = "db_iemr") +@Data +public class PulsePolioCampaign { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "start_date", nullable = false) + private LocalDate startDate; + + @Column(name = "end_date", nullable = false) + private LocalDate endDate; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "number_of_children", nullable = false) + private Integer numberOfChildren = 0; + + + @Column(name = "campaign_photos",columnDefinition = "LONGTEXT") + private String campaignPhotos; + + @Column(name = "created_by", length = 200) + private String createdBy; + + @Column(name = "updated_by", length = 200) + private String updatedBy; + + @Column(name = "created_date", updatable = false) + private LocalDateTime createdDate; + + @Column(name = "updated_date") + private LocalDateTime updatedDate; + + /* ---------- Auto timestamps ---------- */ + + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.updatedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedDate = LocalDateTime.now(); + } + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java index eb8b0107f..d6bcd7b6c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java @@ -45,7 +45,7 @@ public class ScreeningKalaAzar { @Column(name = "house_hold_details_Id",nullable = false) private Long houseHoldDetailsId; - @Column(name = "userID") + @Column(name = "user_id") private Integer userId; @Temporal(TemporalType.DATE) @@ -97,7 +97,7 @@ public class ScreeningKalaAzar { @Column(name = "created_by") private String createdBy; - @Column(name = "diseaseTypeID") + @Column(name = "disease_type_id") private Integer diseaseTypeId; @Column(name = "refer_to_name") diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java index 225a1dfc9..6a485eef7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java @@ -26,7 +26,6 @@ import jakarta.persistence.*; import lombok.Data; - import java.sql.Timestamp; import java.util.Date; @@ -84,25 +83,25 @@ public class ScreeningLeprosy { @Column(name = "beneficiary_statusId") private Integer beneficiaryStatusId; - @Column(name = "beneficiary_status", length = 50) + @Column(name = "beneficiary_status") private String beneficiaryStatus; @Column(name = "date_of_death") private Date dateOfDeath; - @Column(name = "place_of_death", length = 50) + @Column(name = "place_of_death") private String placeOfDeath; @Column(name = "other_place_of_death", columnDefinition = "TEXT") private String otherPlaceOfDeath; - @Column(name = "reason_for_death", length = 50) + @Column(name = "reason_for_death") private String reasonForDeath; @Column(name = "other_reason_for_death", columnDefinition = "TEXT") private String otherReasonForDeath; - @Column(name = "leprosy_symptoms", length = 255) + @Column(name = "leprosy_symptoms") private String leprosySymptoms; @Column(name = "leprosy_symptoms_position") @@ -114,7 +113,7 @@ public class ScreeningLeprosy { @Column(name = "current_visit_number") private Integer currentVisitNumber; - @Column(name = "visit_label", length = 50) + @Column(name = "visit_label") private String visitLabel; @Column(name = "visit_number") @@ -123,7 +122,7 @@ public class ScreeningLeprosy { @Column(name = "is_confirmed") private Boolean isConfirmed; - @Column(name = "leprosy_state", length = 50) + @Column(name = "leprosy_state", length = 255) private String leprosyState; @Temporal(TemporalType.DATE) @@ -143,6 +142,78 @@ public class ScreeningLeprosy { @Column(name = "treatment_status", length = 100) private String treatmentStatus; + @Column(name = "recurrent_ulceration_id") + private Integer recurrentUlcerationId; + + @Column(name = "recurrent_tingling_id") + private Integer recurrentTinglingId; + + @Column(name = "hypopigmented_patch_id") + private Integer hypopigmentedPatchId; + + @Column(name = "thickened_skin_id") + private Integer thickenedSkinId; + + @Column(name = "skin_nodules_id") + private Integer skinNodulesId; + + @Column(name = "skin_patch_discoloration_id") + private Integer skinPatchDiscolorationId; + + @Column(name = "recurrent_numbness_id") + private Integer recurrentNumbnessId; + + @Column(name = "clawing_fingers_id") + private Integer clawingFingersId; + + @Column(name = "tingling_numbness_extremities_id") + private Integer tinglingNumbnessExtremitiesId; + + @Column(name = "inability_close_eyelid_id") + private Integer inabilityCloseEyelidId; + + @Column(name = "difficulty_holding_objects_id") + private Integer difficultyHoldingObjectsId; + + @Column(name = "weakness_feet_id") + private Integer weaknessFeetId; + + @Column(name = "recurrent_ulceration") + private String recurrentUlceration; + + @Column(name = "recurrent_tingling") + private String recurrentTingling; + + @Column(name = "hypopigmented_patch") + private String hypopigmentedPatch; + + @Column(name = "thickened_skin") + private String thickenedSkin; + + @Column(name = "skin_nodules") + private String skinNodules; + + @Column(name = "skin_patch_discoloration") + private String skinPatchDiscoloration; + + @Column(name = "recurrent_numbness") + private String recurrentNumbness; + + @Column(name = "clawing_fingers") + private String clawingFingers; + + @Column(name = "tingling_numbness_extremities") + private String tinglingNumbnessExtremities; + + @Column(name = "inability_close_eyelid") + private String inabilityCloseEyelid; + + @Column(name = "difficulty_holding_objects") + private String difficultyHoldingObjects; + + @Column(name = "weakness_feet") + private String weaknessFeet; + @Column(name = "CreatedBy", length = 100) private String createdBy; diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java new file mode 100644 index 000000000..8310eb65a --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java @@ -0,0 +1,74 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.sql.Timestamp; +import java.time.LocalDate; + +@Entity +@Data +@Table(name = "tb_confirmed_cases",schema = "db_iemr") +public class TBConfirmedCase { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(name = "ben_id", nullable = false) + private Long benId; + + @Column(name = "user_id",nullable = false) + private Integer userId; + + + @Column(name = "regimen_type") + private String regimenType; + + @Column(name = "treatment_start_date") + private LocalDate treatmentStartDate; + + @Column(name = "expected_treatment_completion_date") + private LocalDate expectedTreatmentCompletionDate; + + @Column(name = "follow_up_date") + private LocalDate followUpDate; + + @Column(name = "monthly_follow_up_done") + private String monthlyFollowUpDone; + + @Column(name = "adherence_to_medicines") + private String adherenceToMedicines; + + @Column(name = "any_discomfort") + private Boolean anyDiscomfort; + + @Column(name = "treatment_completed") + private Boolean treatmentCompleted; + + @Column(name = "actual_treatment_completion_date") + private LocalDate actualTreatmentCompletionDate; + + @Column(name = "treatment_outcome") + private String treatmentOutcome; + + @Column(name = "date_of_death") + private LocalDate dateOfDeath; + + @Column(name = "place_of_death") + private String placeOfDeath; + + @Column(name = "reason_for_death") + private String reasonForDeath = "Tuberculosis"; + + @Column(name = "reason_for_not_completing") + private String reasonForNotCompleting; + + @Column(name = "created_at") + private LocalDate createdAt = LocalDate.now(); + + @Column(name = "updated_at") + private LocalDate updatedAt; + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java new file mode 100644 index 000000000..180c3bbed --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java @@ -0,0 +1,29 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; + +@Data +public class TBConfirmedCaseDTO { + + private Long benId; + private Integer userId; + private Integer suspectedTbId; + private String regimenType; + private LocalDate treatmentStartDate; + private LocalDate expectedTreatmentCompletionDate; + private LocalDate followUpDate; + private String monthlyFollowUpDone; + private String adherenceToMedicines; + private Boolean anyDiscomfort; + private Boolean treatmentCompleted; + private LocalDate actualTreatmentCompletionDate; + private String treatmentOutcome; + private LocalDate dateOfDeath; + private String placeOfDeath; + private String reasonForDeath ; + private String reasonForNotCompleting; + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java index 9bf7ea8de..6789f9bf7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java @@ -46,4 +46,37 @@ public class TBScreening { @Column(name = "family_check") private Boolean familySufferingFromTB; + + @Column(name = "rise_of_fever") + private Boolean riseOfFever; + + @Column(name = "loss_of_appetite") + private Boolean lossOfAppetite; + + @Column(name = "age") + private Boolean age; + + @Column(name = "diabetic") + private Boolean diabetic; + + @Column(name = "tobacco_user") + private Boolean tobaccoUser; + + @Column(name = "bmi") + private Boolean bmi; + + @Column(name = "contact_with_tb_patient") + private Boolean contactWithTBPatient; + + @Column(name = "history_of_tb_in_last_five_yrs") + private Boolean historyOfTBInLastFiveYrs; + + @Column(name = "sympotomatic") + private String sympotomatic; + + @Column(name = "asymptomatic") + private String asymptomatic; + + @Column(name = "recommandate_test") + private String recommandateTest; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java b/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java index 7cb945a89..2de2baf82 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java @@ -40,4 +40,40 @@ public class TBSuspected { @Column(name = "followups") private String followUps; + + // Visit Information + @Column(name = "visit_label") + private String visitLabel; + + @Column(name = "type_of_tb_case") + private String typeOfTBCase; + + @Column(name = "reason_for_suspicion", length = 500) + private String reasonForSuspicion; + + + // Chest X-Ray + @Column(name = "is_chest_xray_done") + private Boolean isChestXRayDone; + + @Column(name = "chest_xray_result", length = 100) + private String chestXRayResult; + + // Referral & Confirmation + @Column(name = "referral_facility", length = 200) + private String referralFacility; + + @Column(name = "is_tb_confirmed") + private Boolean isTBConfirmed; + + @Column(name = "is_drtb_confirmed") + private Boolean isDRTBConfirmed; + + @Column(name = "provider_service_map_id") + private Integer providerServiceMapId; + + @Column(name = "is_confirmed") + private Boolean isConfirmed; + + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/M_User.java b/src/main/java/com/iemr/flw/domain/iemr/User.java similarity index 91% rename from src/main/java/com/iemr/flw/domain/iemr/M_User.java rename to src/main/java/com/iemr/flw/domain/iemr/User.java index 0187a6134..d422f9262 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/M_User.java +++ b/src/main/java/com/iemr/flw/domain/iemr/User.java @@ -1,7 +1,6 @@ package com.iemr.flw.domain.iemr; import java.sql.Timestamp; -import java.time.LocalDate; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.gson.annotations.Expose; @@ -14,18 +13,10 @@ import jakarta.persistence.Table; import lombok.Data; -import com.google.gson.annotations.Expose; -import jakarta.persistence.*; -import lombok.Data; -import java.sql.Date; -import java.sql.Timestamp; -import java.time.LocalDate; - @Entity -@Table(name = "m_User", schema = "db_iemr") +@Table(name = "m_user", schema = "db_iemr") @Data -public class M_User { - +public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose @@ -144,11 +135,11 @@ public class M_User { @Column(name = "failed_attempt", insertable = false) private Integer failedAttempt; - public M_User() { + public User() { // TODO Auto-generated constructor stub } - public M_User(Integer userID, String userName) { + public User(Integer userID, String userName) { // TODO Auto-generated constructor stub this.userID = userID; this.userName = userName; diff --git a/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java b/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java index f995a71dc..9ab6d5cb3 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java +++ b/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java @@ -23,6 +23,9 @@ public class UwinSession { @Column(name = "date", nullable = false) private Timestamp date; + @Column(name = "session_date", nullable = false) + private Timestamp sessionDate; + @Column(name = "place", nullable = false) private String place; diff --git a/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java b/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java index 488b33c4e..758cc449a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java @@ -37,6 +37,39 @@ public class VHNDForm { @Column(name = "form_type") private String formType; + @Column(name = "vhnd_place_id") + private Integer vhndPlaceId; + + @Column(name = "pregnant_women_anc") + private String pregnantWomenAnc; + + @Column(name = "lactating_mothers_pnc") + private String lactatingMothersPnc; + + @Column(name = "children_immunization") + private String childrenImmunization; + + @Column(name = "select_all_education") + private Boolean selectAllEducation; + + @Column(name = "knowledge_balanced_diet") + private String knowledgeBalancedDiet; + + @Column(name = "care_during_pregnancy") + private String careDuringPregnancy; + + @Column(name = "importance_breastfeeding") + private String importanceBreastfeeding; + + @Column(name = "complementary_feeding") + private String complementaryFeeding; + + @Column(name = "hygiene_sanitation") + private String hygieneSanitation; + + @Column(name = "family_planning_healthcare") + private String familyPlanningHealthcare; + @Column(name = "created_by") private String createdBy; diff --git a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java index 5b53b27ed..858554daf 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java @@ -1,6 +1,7 @@ package com.iemr.flw.domain.iemr; import jakarta.persistence.*; +import jakarta.xml.bind.annotation.XmlAccessorOrder; import lombok.Data; import org.hibernate.annotations.CreationTimestamp; @@ -43,4 +44,26 @@ public class VhncForm { @Column(name = "form_type") private String formType; + + @Column(name = "village_name") + private String villageName; + + @Column(name = "anm") + private Integer anm; + + @Column(name = "aww") + private Integer aww; + + @Column(name = "no_of_pragnent_women") + private Integer noOfPragnentWoment; + + @Column(name = "no_of_lacting_mother") + private Integer noOfLactingMother; + + @Column(name = "no_of_committee") + private Integer noOfCommittee; + + @Column(name = "followup_previous") + private Boolean followupPrevius; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/abhaBeneficiary/AbhaBeneficiaryDTO.java b/src/main/java/com/iemr/flw/dto/abhaBeneficiary/AbhaBeneficiaryDTO.java new file mode 100644 index 000000000..dab9dec3b --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/abhaBeneficiary/AbhaBeneficiaryDTO.java @@ -0,0 +1,65 @@ +package com.iemr.flw.dto.abhaBeneficiary; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class AbhaBeneficiaryDTO { + @JsonProperty("personName") + private String personName; + + private String firstName; + + private String lastName; + + @JsonProperty("age") + private String age; + + @JsonProperty("address") + private String address; + + @JsonProperty("district") + private String district; + + @JsonProperty("mobileNo") + private String mobileNo; + + @JsonProperty("block") + private String block; + + @JsonProperty("cardNo") + private String cardNo; + + @JsonProperty("villagename") + private String villagename; + + @JsonProperty("gender") + private String gender; + + @JsonProperty("district_Code") + private String districtCode; + + @JsonProperty("block_Code") + private String blockCode; + + @JsonProperty("village_Code") + private String villageCode; + + @JsonProperty("rural_Urban") + private String ruralUrban; + + @JsonProperty("abhaId") + private String abhaId; + + @JsonProperty("vvs") + private String vvs; + + @JsonProperty("familyid") + private String familyid; + + @JsonProperty("dob") + @JsonAlias("dob_secc") + private String dob; + +} diff --git a/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java b/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java index 00e452c52..d1a654ec6 100644 --- a/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java +++ b/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java @@ -12,6 +12,36 @@ public class GetBenRequestHandler { private Integer ashaId; + private Long activityId; + + private Integer month; + + private Integer year; + + public Integer getMonth() { + return month; + } + + public void setMonth(Integer month) { + this.month = month; + } + + public Integer getYear() { + return year; + } + + public void setYear(Integer year) { + this.year = year; + } + + public Long getActivityId() { + return activityId; + } + + public void setActivityId(Long activityId) { + this.activityId = activityId; + } + public Integer getAshaId() { return ashaId; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java index f028655fb..b4cf0033a 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java @@ -63,6 +63,8 @@ public class ANCVisitDTO { private Timestamp visitDate; private Timestamp dateSterilisation; private Boolean isYesOrNo; + private String placeOfAnc; + private Integer placeOfAncId; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/AbhaRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AbhaRequestDTO.java new file mode 100644 index 000000000..9ec31c6fd --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AbhaRequestDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class AbhaRequestDTO { + private String cardNo; + private Long houseHoldId; + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java new file mode 100644 index 000000000..76aff81da --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java @@ -0,0 +1,15 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class AncCounsellingCareDTO { + private String formId; + private Long beneficiaryId; + private String visitDate; + private AncCounsellingCareListDTO fields; + +} + + + diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java new file mode 100644 index 000000000..981e34e2b --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java @@ -0,0 +1,79 @@ +package com.iemr.flw.dto.iemr; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +@Data +public class AncCounsellingCareListDTO { + + @SerializedName("home_visit_date") + private String homeVisitDate; + + @SerializedName("select_all") + private String selectAll; + + @SerializedName("swelling") + private String swelling; + + @SerializedName("high_bp") + private String highBp; + + @SerializedName("convulsions") + private String convulsions; + + @SerializedName("anemia") + private String anemia; + + @SerializedName("reduced_fetal_movement") + private String reducedFetalMovement; + + @SerializedName("age_risk") + private String ageRisk; + + @SerializedName("child_gap") + private String childGap; + + @SerializedName("short_height") + private String shortHeight; + + @SerializedName("pre_preg_weight") + private String prePregWeight; + + @SerializedName("bleeding") + private String bleeding; + + @SerializedName("miscarriage_history") + private String miscarriageHistory; + + @SerializedName("four_plus_delivery") + private String fourPlusDelivery; + + @SerializedName("first_delivery") + private String firstDelivery; + + @SerializedName("twin_pregnancy") + private String twinPregnancy; + + @SerializedName("c_section_history") + private String cSectionHistory; + + @SerializedName("pre_existing_disease") + private String preExistingDisease; + + @SerializedName("fever_malaria") + private String feverMalaria; + + @SerializedName("jaundice") + private String jaundice; + + @SerializedName("sickle_cell") + private String sickleCell; + + @SerializedName("prolonged_labor") + private String prolongedLabor; + + @SerializedName("malpresentation") + private String malpresentation; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java new file mode 100644 index 000000000..2e0195582 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java @@ -0,0 +1,17 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +import java.util.Map; + +@Data +public class AncCounsellingCareResponseDTO { + private String formId; + private Long beneficiaryId; + private String visitDate; + private Map fields; // for dynamic form fields + +} + + + diff --git a/src/main/java/com/iemr/flw/dto/iemr/AshaByFacilityRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AshaByFacilityRequestDTO.java new file mode 100644 index 000000000..9ae46ad4c --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AshaByFacilityRequestDTO.java @@ -0,0 +1,11 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class AshaByFacilityRequestDTO { + private Integer facilityId; + private Integer month; + private Integer year; + private Integer approvalStatus; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java b/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java index 122f652d8..e39f06412 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java @@ -54,6 +54,8 @@ public class CdrDTO { private String deathCertImage1; private String deathCertImage2; + private String cdrImage; + private Timestamp updatedDate; diff --git a/src/main/java/com/iemr/flw/dto/iemr/ChronicDiseaseVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/ChronicDiseaseVisitDTO.java new file mode 100644 index 000000000..2a2790ad7 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/ChronicDiseaseVisitDTO.java @@ -0,0 +1,44 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Column; +import lombok.Data; + +import java.time.LocalDate; + +@Data +public class ChronicDiseaseVisitDTO { + + @JsonProperty("id") + private Long id; + + @JsonProperty("benId") + private Long benId; + + @JsonProperty("hhId") + private Long hhId; + + @JsonProperty("formId") + private String formId; + + @JsonProperty("version") + private Integer version; + + @JsonProperty("visitNo") + private Integer visitNo; + + @JsonProperty("followUpNo") + private Integer followUpNo; + + @Column(name = "followUpDate") + private LocalDate followUpDate; + + @JsonProperty("diagnosisCodes") + private String diagnosisCodes; + + @JsonProperty("treatmentStartDate") + private String treatmentStartDate; // yyyy-MM-dd + + @JsonProperty("formDataJson") + private String formDataJson; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java index 941721ca1..5e94697a1 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java @@ -10,7 +10,6 @@ public class DeliveryOutcomeDTO { private Long id; private Long benId; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") private Timestamp dateOfDelivery; private String timeOfDelivery; private String placeOfDelivery; diff --git a/src/main/java/com/iemr/flw/dto/iemr/DiseaseLeprosyDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DiseaseLeprosyDTO.java index c0acbe716..47489c54e 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DiseaseLeprosyDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DiseaseLeprosyDTO.java @@ -72,4 +72,28 @@ public class DiseaseLeprosyDTO { private Timestamp createdDate; private String modifiedBy; private Timestamp lastModDate; + private Integer recurrentUlcerationId; + private Integer recurrentTinglingId; + private Integer hypopigmentedPatchId; + private Integer thickenedSkinId; + private Integer skinNodulesId; + private Integer skinPatchDiscolorationId; + private Integer recurrentNumbnessId; + private Integer clawingFingersId; + private Integer tinglingNumbnessExtremitiesId; + private Integer inabilityCloseEyelidId; + private Integer difficultyHoldingObjectsId; + private Integer weaknessFeetId; + private String recurrentUlceration; + private String recurrentTingling; + private String hypopigmentedPatch; + private String thickenedSkin; + private String skinNodules; + private String skinPatchDiscoloration; + private String recurrentNumbness; + private String clawingFingers; + private String tinglingNumbnessExtremities; + private String inabilityCloseEyelid; + private String difficultyHoldingObjects; + private String weaknessFeet; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupListDTO.java index 3480aa0ba..12cba394d 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupListDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupListDTO.java @@ -3,13 +3,16 @@ import com.google.gson.annotations.SerializedName; import lombok.Data; +import java.util.List; +import java.util.stream.Collectors; + @Data public class EyeCheckupListDTO { @SerializedName("visit_date") private String visit_date; @SerializedName("symptoms_observed") - private String symptoms_observed; + private Object symptoms_observed; @SerializedName("eye_affected") private String eye_affected; @@ -26,4 +29,16 @@ public class EyeCheckupListDTO { @SerializedName("discharge_summary_upload") private String discharge_summary_upload; + public String getSymptomsAsString() { + if (symptoms_observed == null) return null; + + if (symptoms_observed instanceof List) { + return ((List) symptoms_observed) + .stream() + .map(Object::toString) + .collect(Collectors.joining(", ")); + } + return symptoms_observed.toString(); + } + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupRequestDTO.java index f0c6d8bb5..2bd9f2c8a 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupRequestDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupRequestDTO.java @@ -9,6 +9,7 @@ public class EyeCheckupRequestDTO { private Long houseHoldId; private String visitDate; private String userName; + private String eyeSide; private EyeCheckupListDTO fields; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java new file mode 100644 index 000000000..2e53ee290 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class FilariasisCampaignDTO { + private Long id; + private String visitDate; + private FilariasisCampaignListDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListDTO.java new file mode 100644 index 000000000..81438df93 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListDTO.java @@ -0,0 +1,30 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class FilariasisCampaignListDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate startDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate endDate; + + @JsonProperty("no_of_families") + private String numberOfFamilies; + + @JsonProperty("no_of_individuals") + private String numberOfIndividuals; + + @JsonProperty("mda_photos") + private List mdaPhotos; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListResponseDTO.java new file mode 100644 index 000000000..700d46653 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListResponseDTO.java @@ -0,0 +1,31 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class FilariasisCampaignListResponseDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate startDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate endDate; + + @JsonProperty("no_of_families") + private Double numberOfFamilies; + + @JsonProperty("no_of_individuals") + private Double numberOfIndividuals; + + @JsonProperty("mda_photos") + private List mdaPhotos; + + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisResponseDTO.java new file mode 100644 index 000000000..7b6dc5aa9 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisResponseDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class FilariasisResponseDTO { + private Long id; + private Long houseHoldId; + private FilariasisCampaignListResponseDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java index acc54ca89..172132e07 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java @@ -47,7 +47,7 @@ public class HbycDTO { private String other_place_of_death; @SerializedName("baby_weight") - private BigDecimal baby_weight; + private Integer baby_weight; @SerializedName("is_child_sick") private String is_child_sick; diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java index 58da99587..354e762d5 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java @@ -1,5 +1,7 @@ package com.iemr.flw.dto.iemr; +import jakarta.persistence.Column; +import jakarta.persistence.Transient; import lombok.Data; import java.sql.Timestamp; @@ -30,5 +32,35 @@ public class IncentiveRecordDTO { private Timestamp updatedDate; private String updatedBy; + + private Boolean isEligible; + + private Boolean isDefaultActivity; + + private Integer approvalStatus; + + private Integer verifiedByUserId; + + private String verifiedByUserName; + + private String activityDec; + + private String groupName; + + private String reason; + + private String otherReason; + + private Boolean isClaimed; + + private Timestamp approvalDate; + + private Timestamp calimedDate; + + private String supervisorRole; + + + + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingRequestDTO.java index c08c8d64e..e4ca6af5e 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingRequestDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingRequestDTO.java @@ -1,17 +1,24 @@ package com.iemr.flw.dto.iemr; import lombok.Data; +import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; import java.sql.Timestamp; import java.time.LocalDate; +import java.util.List; @Data public class MaaMeetingRequestDTO { + private Long id; private LocalDate meetingDate; private String place; private Integer participants; private MultipartFile[] meetingImages; // up to 5 images private Integer ashaId; + private String villageName; + private Integer noOfPragnentWomen; + private Integer noOfLactingMother; + private String mitaninActivityCheckList; private String createdBY; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingResponseDTO.java index 9ba81ad82..b56356c2d 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingResponseDTO.java @@ -35,6 +35,11 @@ public class MaaMeetingResponseDTO { example = "[\"iVBORw0KGgoAAAANSUhEUgAA...\", \"iVBORw0KGgoAAAANSUhEUgBB...\"]") private List meetingImages; + private String villageName; + private String noOfPragnentWomen; + private String noOfLactingMother; + private String mitaninActivityCheckList; + @Column(name = "created_by") private String createdBy; diff --git a/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java index 5b07e40a3..e59047aba 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java @@ -35,4 +35,10 @@ public class MdsrDTO { private Timestamp updatedDate; private String updatedBy; + + private String mdsr1File; + + private String mdsr2File; + + private String mdsrDeathCertFile; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignDTO.java new file mode 100644 index 000000000..dbd83c26b --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class OrsCampaignDTO { + private Long id; + private String visitDate; + private OrsCampaignListDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListDTO.java new file mode 100644 index 000000000..552c4fc8a --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListDTO.java @@ -0,0 +1,30 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.util.List; + +@Data +public class OrsCampaignListDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate StartDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate EndDate; + + @JsonProperty("number_of_families") + private String NumberOfFamilies; + + @JsonProperty("campaign_photos") + private List campaignPhotos; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListResponseDTO.java new file mode 100644 index 000000000..e72fb04c6 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListResponseDTO.java @@ -0,0 +1,25 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class OrsCampaignListResponseDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate StartDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate EndDate; + + @JsonProperty("number_of_families") + private Double NumberOfFamilies; + + @JsonProperty("campaign_photos") + private List campaignPhotos; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignResponseDTO.java new file mode 100644 index 000000000..5c8b954dd --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignResponseDTO.java @@ -0,0 +1,9 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class OrsCampaignResponseDTO { + private Long id; + private OrsCampaignListResponseDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionListDTO.java index 25ab11b58..45ef54299 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionListDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionListDTO.java @@ -10,7 +10,7 @@ public class OrsDistributionListDTO { private String visit_date; @SerializedName("num_under5_children") - private Double num_under5_children; + private Double num_under5_children=1.0; @SerializedName("num_ors_packets") private Double num_ors_packets; diff --git a/src/main/java/com/iemr/flw/dto/iemr/PaymentItem.java b/src/main/java/com/iemr/flw/dto/iemr/PaymentItem.java new file mode 100644 index 000000000..2bb0eceaa --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PaymentItem.java @@ -0,0 +1,18 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class PaymentItem { + @JsonProperty("activity_code") + public String activityCode; + + @JsonProperty("count") + public String count; + + @JsonProperty("incentive_amount") + public String incentiveAmount; + + + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/PaymentRequest.java b/src/main/java/com/iemr/flw/dto/iemr/PaymentRequest.java new file mode 100644 index 000000000..88218b26a --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PaymentRequest.java @@ -0,0 +1,43 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class PaymentRequest { + @JsonProperty("submission_id") + public String submissionId; + + @JsonProperty("partner_code") + public String partnerCode; + + @JsonProperty("period") + public Period period; + + @JsonProperty("asha_id") + public String ashaId; + + @JsonProperty("generated_at") + public String generatedAt; + + @JsonProperty("verified_by") + public VerifiedBy verifiedBy; + + @JsonProperty("items") + public List items; + + public PaymentRequest() {} + + public PaymentRequest(String submissionId, String partnerCode, Period period, + String ashaId, String generatedAt, + VerifiedBy verifiedBy, List items) { + this.submissionId = submissionId; + this.partnerCode = partnerCode; + this.period = period; + this.ashaId = ashaId; + this.generatedAt = generatedAt; + this.verifiedBy = verifiedBy; + this.items = items; + } + } + diff --git a/src/main/java/com/iemr/flw/dto/iemr/PendingActivityDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PendingActivityDTO.java new file mode 100644 index 000000000..5fcdd5375 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PendingActivityDTO.java @@ -0,0 +1,15 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@Data +public class PendingActivityDTO { + private Long id; + private Integer userId; + private List images; + private String moduleName; + private String activityName; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/Period.java b/src/main/java/com/iemr/flw/dto/iemr/Period.java new file mode 100644 index 000000000..049e35be0 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/Period.java @@ -0,0 +1,19 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class Period { + @JsonProperty("start") + public String start; + + @JsonProperty("end") + public String end; + + public Period() {} + + + + } + diff --git a/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java index 00830988c..b08386c6e 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java @@ -1,5 +1,6 @@ package com.iemr.flw.dto.iemr; +import jakarta.persistence.Column; import lombok.Data; @Data @@ -8,8 +9,13 @@ public class PhcReviewMeetingFormDTO { private String phcReviewDate; private String place; private Integer noOfBeneficiariesAttended; + private String villageName; + private String mitaninHistory; + private String mitaninActivityCheckList; + private Integer placeId; private String image1; private String image2; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignDTO.java new file mode 100644 index 000000000..7f6cfc87b --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class PolioCampaignDTO { + private Long id; + private String visitDate; + private PolioCampaignListDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListDTO.java new file mode 100644 index 000000000..a42ef3c63 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListDTO.java @@ -0,0 +1,28 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class PolioCampaignListDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate startDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate endDate; + + @JsonProperty("children_vaccinated") + private String numberOfChildren; + + @JsonProperty("campaign_photos") + private List campaignPhotos; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListResponseDTO.java new file mode 100644 index 000000000..f27468f3f --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListResponseDTO.java @@ -0,0 +1,25 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class PolioCampaignListResponseDTO { + @JsonProperty("start_date") + private LocalDate startDate; + + @JsonProperty("end_date") + private LocalDate endDate; + + @JsonProperty("children_vaccinated") + private Double numberOfChildren; + + @JsonProperty("campaign_photos") + private List campaignPhotos; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignResponseDTO.java new file mode 100644 index 000000000..a65042364 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignResponseDTO.java @@ -0,0 +1,9 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class PolioCampaignResponseDTO { + private Long id; + private PolioCampaignListResponseDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedCasesResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedCasesResponseDTO.java new file mode 100644 index 000000000..42504dcdb --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedCasesResponseDTO.java @@ -0,0 +1,11 @@ +package com.iemr.flw.dto.iemr; + +import com.iemr.flw.domain.iemr.TBConfirmedCase; +import lombok.Data; + +import java.util.List; +@Data +public class TBConfirmedCasesResponseDTO { + Integer userId ; + List tbConfirmedCases; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java new file mode 100644 index 000000000..d3e76a4a7 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java @@ -0,0 +1,13 @@ +package com.iemr.flw.dto.iemr; + +import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; +import lombok.Data; +import java.util.List; + +@Data +public class TBConfirmedRequestDTO { + + private Long userId; + + private List tbConfirmedList; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java index 270526bdc..36f48dfc5 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java @@ -29,91 +29,15 @@ public class TBScreeningDTO { private Boolean familySufferingFromTB; - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getBenId() { - return benId; - } - - public void setBenId(Long benId) { - this.benId = benId; - } - - public Timestamp getVisitDate() { - return visitDate; - } - - public void setVisitDate(Timestamp visitDate) { - this.visitDate = visitDate; - } - - public Boolean getCoughMoreThan2Weeks() { - return coughMoreThan2Weeks; - } - - public void setCoughMoreThan2Weeks(Boolean coughMoreThan2Weeks) { - this.coughMoreThan2Weeks = coughMoreThan2Weeks; - } - - public Boolean getBloodInSputum() { - return bloodInSputum; - } - - public void setBloodInSputum(Boolean bloodInSputum) { - this.bloodInSputum = bloodInSputum; - } - - public Boolean getFeverMoreThan2Weeks() { - return feverMoreThan2Weeks; - } - - public void setFeverMoreThan2Weeks(Boolean feverMoreThan2Weeks) { - this.feverMoreThan2Weeks = feverMoreThan2Weeks; - } - - public Boolean getLossOfWeight() { - return lossOfWeight; - } - - public void setLossOfWeight(Boolean lossOfWeight) { - this.lossOfWeight = lossOfWeight; - } - - public Boolean getNightSweats() { - return nightSweats; - } - - public void setNightSweats(Boolean nightSweats) { - this.nightSweats = nightSweats; - } - - public Boolean getHistoryOfTb() { - return historyOfTb; - } - - public void setHistoryOfTb(Boolean historyOfTb) { - this.historyOfTb = historyOfTb; - } - - public Boolean getTakingAntiTBDrugs() { - return takingAntiTBDrugs; - } - - public void setTakingAntiTBDrugs(Boolean takingAntiTBDrugs) { - this.takingAntiTBDrugs = takingAntiTBDrugs; - } - - public Boolean getFamilySufferingFromTB() { - return familySufferingFromTB; - } - - public void setFamilySufferingFromTB(Boolean familySufferingFromTB) { - this.familySufferingFromTB = familySufferingFromTB; - } + private Boolean riseOfFever; + private Boolean lossOfAppetite; + private Boolean age; + private Boolean diabetic; + private Boolean tobaccoUser; + private Boolean bmi; + private Boolean contactWithTBPatient; + private Boolean historyOfTBInLastFiveYrs; + private String sympotomatic; + private String asymptomatic; + private String recommandateTest; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java index 8d224a9ce..29fb25f6e 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java @@ -10,18 +10,20 @@ public class TBSuspectedDTO { private Long id; private Long benId; - + private String visitLabel; private Timestamp visitDate; - + private String typeOfTBCase; + private String reasonForSuspicion; private Boolean isSputumCollected; - private String sputumSubmittedAt; - private String nikshayId; - private String sputumTestResult; - + private Boolean isChestXRayDone; + private String chestXRayResult; + private String referralFacility; + private Boolean isTBConfirmed; + private Boolean isConfirmed; + private Boolean isDRTBConfirmed; private Boolean referred; - private String followUps; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/UpdateApprovalRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/UpdateApprovalRequestDTO.java new file mode 100644 index 000000000..ff7867301 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/UpdateApprovalRequestDTO.java @@ -0,0 +1,14 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class UpdateApprovalRequestDTO { + private Integer ashaId; + private Integer month; + private Integer year; + private Integer approvalStatus; + private String incentiveIds; + private String reason; + private String otherReason; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java new file mode 100644 index 000000000..052b7d12f --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java @@ -0,0 +1,11 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class UpdateClaimedStatusRequestDTO { + private Integer ashaId; + private Integer month; + private Integer year; + private boolean isClaimed; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java b/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java index 81d749030..ead3ddc06 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java @@ -4,6 +4,8 @@ import lombok.Getter; import lombok.Setter; +import java.util.Map; + @Data @Getter @Setter @@ -23,6 +25,7 @@ public class UserServiceRoleDTO { private String blockName; private String villageId; private String villageName; + private Map facilityData; public UserServiceRoleDTO(Integer userId, String name, String userName, Integer stateId, String stateName, Integer workingDistrictId, String workingDistrictName, Short serviceProviderId, Integer roleId, String roleName, Integer providerServiceMapId, Integer blockId, String blockName, String villageId, String villageName) { this.userId = userId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java index 0dec7976a..bee7f2475 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java @@ -24,6 +24,7 @@ */ package com.iemr.flw.dto.iemr; +import jakarta.persistence.Column; import lombok.Data; @Data @@ -33,6 +34,17 @@ public class VHNDFormDTO { private Integer noOfBeneficiariesAttended; private String image1; private String image2; + private Integer vhndPlaceId; + private String pregnantWomenAnc; + private String lactatingMothersPnc; + private String childrenImmunization; + private Boolean selectAllEducation; + private String knowledgeBalancedDiet; + private String careDuringPregnancy; + private String importanceBreastfeeding; + private String complementaryFeeding; + private String hygieneSanitation; + private String familyPlanningHealthcare; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/VerifiedBy.java b/src/main/java/com/iemr/flw/dto/iemr/VerifiedBy.java new file mode 100644 index 000000000..e64deb39c --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/VerifiedBy.java @@ -0,0 +1,17 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class VerifiedBy { + @JsonProperty("employee_id") + public String employeeId; + + @JsonProperty("name") + public String name; + + public VerifiedBy() {} + + + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java index 8a12be966..a2515b421 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java @@ -34,4 +34,12 @@ public class VhncFormDTO { private Integer noOfBeneficiariesAttended; private String image1; private String image2; + private String villageName; + private Integer anm; + private Integer aww; + private Integer noOfPragnentWoment; + private Integer noOfLactingMother; + private Integer noOfCommittee; + private Boolean followupPrevius; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/masterEnum/GroupName.java b/src/main/java/com/iemr/flw/masterEnum/GroupName.java index 8d6736eb3..e53733b02 100644 --- a/src/main/java/com/iemr/flw/masterEnum/GroupName.java +++ b/src/main/java/com/iemr/flw/masterEnum/GroupName.java @@ -33,3 +33,6 @@ public String getDisplayName() { } + + + diff --git a/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java b/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java new file mode 100644 index 000000000..e40ecc980 --- /dev/null +++ b/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java @@ -0,0 +1,35 @@ +package com.iemr.flw.masterEnum; + +public enum IncentiveApprovalStatus { + + VERIFIED(101, "Verified"), + PENDING(102, "Pending"), + REJECTED(103, "Rejected"), + OVERDUE(104, "Overdue"); + + private final int code; + private final String label; + + IncentiveApprovalStatus(int code, String label) { + this.code = code; + this.label = label; + } + + public int getCode() { + return code; + } + + public String getLabel() { + return label; + } + + // 🔥 Reverse lookup (code → enum) + public static IncentiveApprovalStatus fromCode(int code) { + for (IncentiveApprovalStatus status : values()) { + if (status.code == code) { + return status; + } + } + throw new IllegalArgumentException("Invalid approval status code: " + code); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/masterEnum/IncentiveName.java b/src/main/java/com/iemr/flw/masterEnum/IncentiveName.java new file mode 100644 index 000000000..052ab011c --- /dev/null +++ b/src/main/java/com/iemr/flw/masterEnum/IncentiveName.java @@ -0,0 +1,139 @@ +package com.iemr.flw.masterEnum; + +public enum IncentiveName { + + // ---------------- CHILD HEALTH ---------------- + HBNC_0_42_DAYS(GroupName.CHILD_HEALTH), + HBYC_QUARTERLY_VISITS(GroupName.CHILD_HEALTH), + SNCU_LBW_FOLLOWUP(GroupName.CHILD_HEALTH), + SAM_REFERRAL_NRC(GroupName.CHILD_HEALTH), + CHILD_DEATH_REPORTING(GroupName.CHILD_HEALTH), + E_HBNC_CACHAR(GroupName.CHILD_HEALTH), + MAA_QUARTERLY_MEETING(GroupName.CHILD_HEALTH), + NATIONAL_DEWORMING_DAY(GroupName.CHILD_HEALTH), + ORS_DISTRIBUTION(GroupName.CHILD_HEALTH), + NATIONAL_IRON_PLUS(GroupName.CHILD_HEALTH), + NIPI_CHILDREN(GroupName.CHILD_HEALTH), + + // ---------------- IMMUNIZATION ---------------- + FULL_IMMUNIZATION_0_1(GroupName.IMMUNIZATION), + COMPLETE_IMMUNIZATION_1_2(GroupName.IMMUNIZATION), + DPT_IMMUNIZATION_5_YEARS(GroupName.IMMUNIZATION), + CHILD_MOBILIZATION_SESSIONS(GroupName.IMMUNIZATION), + + // ---------------- MATERNAL HEALTH ---------------- + ANC_REGISTRATION_1ST_TRIM(GroupName.MATERNAL_HEALTH), + FULL_ANC(GroupName.MATERNAL_HEALTH), + COMPREHENSIVE_ABORTION_CARE(GroupName.MATERNAL_HEALTH), + INST_DELIVERY_HRP(GroupName.MATERNAL_HEALTH), + EPMSMA_INST_DELIVERY(GroupName.MATERNAL_HEALTH), + EPMSMA_HRP_IDENTIFIED(GroupName.MATERNAL_HEALTH), + MATERNAL_DEATH_REPORT(GroupName.MATERNAL_HEALTH), + MH_MISOPROSTOL(GroupName.MATERNAL_HEALTH), + MH_EARLY_REG_BANK(GroupName.MATERNAL_HEALTH), + MH_ANC_3RD_TRIM(GroupName.MATERNAL_HEALTH), + MH_MOTIVATE_INST_DEL(GroupName.MATERNAL_HEALTH), + MH_HR_POSTNATAL(GroupName.MATERNAL_HEALTH), + + // ---------------- JSY ---------------- + JSY_1ST_DEL_ANC_RURAL(GroupName.JSY), + JSY_1ST_DEL_INST_RURAL(GroupName.JSY), + JSY_2ND_DEL_ANC_RURAL(GroupName.JSY), + JSY_2ND_DEL_INST_RURAL(GroupName.JSY), + JSY_3RD_DEL_ANC_RURAL(GroupName.JSY), + JSY_3RD_DEL_INST_RURAL(GroupName.JSY), + JSY_4TH_DEL_ANC_RURAL(GroupName.JSY), + JSY_4TH_DEL_INST_RURAL(GroupName.JSY), + JSY_ANC_URBAN(GroupName.JSY), + JSY_INST_URBAN(GroupName.JSY), + + // ---------------- FAMILY PLANNING ---------------- + FP_ANC_MPA1(GroupName.FAMILY_PLANNING), + FP_ANC_MPA2(GroupName.FAMILY_PLANNING), + FP_ANC_MPA3(GroupName.FAMILY_PLANNING), + FP_ANC_MPA4(GroupName.FAMILY_PLANNING), + FP_ANC_MPA5(GroupName.FAMILY_PLANNING), + FIRST_SECOND_CHILD_GAP(GroupName.FAMILY_PLANNING), + FP_DELAY_2Y(GroupName.FAMILY_PLANNING), + FP_LIMIT_2CHILD(GroupName.FAMILY_PLANNING), + FP_PPIUCD(GroupName.FAMILY_PLANNING), + FP_PAIUCD(GroupName.FAMILY_PLANNING), + FP_CONDOM(GroupName.FAMILY_PLANNING), + FP_ORALPILLS(GroupName.FAMILY_PLANNING), + FP_EC(GroupName.FAMILY_PLANNING), + FP_FEMALE_STER(GroupName.FAMILY_PLANNING), + FP_PPS(GroupName.FAMILY_PLANNING), + FP_MINILAP(GroupName.FAMILY_PLANNING), + FP_MALE_STER(GroupName.FAMILY_PLANNING), + FP_EC_SURVEY(GroupName.FAMILY_PLANNING), + FP_SAAS_BAHU(GroupName.FAMILY_PLANNING), + FP_NP_KIT(GroupName.FAMILY_PLANNING), + + // ---------------- ADOLESCENT HEALTH ---------------- + AH_SANITARY(GroupName.ADOLESCENT_HEALTH), + AH_PEER_ED(GroupName.ADOLESCENT_HEALTH), + AH_MOBILIZE(GroupName.ADOLESCENT_HEALTH), + + // ---------------- ASHA ROUTINE ---------------- + ASHA_MONTHLY_ROUTINE(GroupName.ASHA_MONTHLY_ROUTINE), + + // ---------------- UMBRELLA PROGRAMMES ---------------- + NPCB_GOVT_CATARACT(GroupName.UMBRELLA_PROGRAMMES), + NPCB_PRIVATE_CATARACT(GroupName.UMBRELLA_PROGRAMMES), + DSTB_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + DRTB_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + INFORMANT_INCENTIVE(GroupName.UMBRELLA_PROGRAMMES), + TPT_PROVIDING(GroupName.UMBRELLA_PROGRAMMES), + BANK_ACCOUNT_NPY(GroupName.UMBRELLA_PROGRAMMES), + HOUSE_TO_HOUSE_SURVEY(GroupName.UMBRELLA_PROGRAMMES), + NLEP_TRAINING(GroupName.UMBRELLA_PROGRAMMES), + NLEP_CASE_DETECTION(GroupName.UMBRELLA_PROGRAMMES), + NLEP_PB_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + NLEP_MB_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + LEPROSY_PARTIAL_ASHA(GroupName.UMBRELLA_PROGRAMMES), + NVBDCP_SLIDE_COLLECTION(GroupName.UMBRELLA_PROGRAMMES), + NVBDCP_MALARIA_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + AES_JE_REFERRAL(GroupName.UMBRELLA_PROGRAMMES), + DENGUE_CHIKUNGUNYA(GroupName.UMBRELLA_PROGRAMMES), + NIDDCP_SALT_TEST(GroupName.UMBRELLA_PROGRAMMES), + + // ---------------- NCD ---------------- + NCD_POP_ENUMERATION(GroupName.NCD), + NCD_FOLLOWUP_TREATMENT(GroupName.NCD), + NCD_NEW_PATIENT_MEDICATION_SUPPORT(GroupName.NCD), + + // ---------------- ADDITIONAL INCENTIVE ---------------- + ADDITIONAL_ASHA_INCENTIVE(GroupName.ADDITIONAL_INCENTIVE), + + // ---------------- OTHER INCENTIVES ---------------- + ABHA_ID_CREATION(GroupName.OTHER_INCENTIVES), + MOBILE_BILL_REIMB(GroupName.OTHER_INCENTIVES), + + // ---------------- ACTIVITY ---------------- + ANC_FOUR_CHECKUPS_SUPPORT(GroupName.ACTIVITY), + INST_DELIVERY_ESCORT(GroupName.ACTIVITY), + FILARIASIS_MEDICINE_DISTRIBUTION(GroupName.ACTIVITY), + VHND_PARTICIPATION(GroupName.ACTIVITY), + CLUSTER_MEETING(GroupName.ACTIVITY), + VHSNC_MEETING(GroupName.ACTIVITY), + MITANIN_REGISTER(GroupName.ACTIVITY), + HWC_REFERRAL_10_CASES(GroupName.ACTIVITY), + LACTATING_MOTHERS_HOME_VISIT(GroupName.ACTIVITY), + MITANIN_REGISTER_5_INFO_FILL(GroupName.ACTIVITY), + HIGH_RISK_POSTPARTUM_HEALTH_CHECK(GroupName.ACTIVITY), + MOSQUITO_NET_DISTRIBUTION_MOBILIZATION(GroupName.ACTIVITY), + HIGH_RISK_POSTPARTUM_CARE(GroupName.ACTIVITY), + MONTHLY_HONORARIUM(GroupName.ACTIVITY), + FULL_ANC_45(GroupName.ACTIVITY), + MH_MOTIVATE_INST_DEL_46(GroupName.ACTIVITY); + + private final GroupName groupName; + + IncentiveName(GroupName groupName) { + this.groupName = groupName; + } + + public GroupName getGroupName() { + return groupName; + } +} diff --git a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java index 96301fb3c..e4ce22f04 100644 --- a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java +++ b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java @@ -12,7 +12,10 @@ import java.math.BigInteger; import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.Optional; +import java.util.stream.Stream; @Repository public interface BeneficiaryRepo extends JpaRepository { @@ -22,22 +25,30 @@ public interface BeneficiaryRepo extends JpaRepository findById(Long benID); + List findByHouseoldId(Long houseHoldId); + List findByBenficieryid(Long benID); + @Query(value = "SELECT beneficiaryRegID FROM db_identity.i_beneficiarydetails_rmnch WHERE BeneficiaryId = :benId", nativeQuery = true) Long getBenRegIdFromBenId(@Param("benId") Long benId); @Query(nativeQuery = true, value = " SELECT userid FROM db_iemr.m_user WHERE UserName = :userName ") Integer getUserIDByUserName(@Param("userName") String userName); - @Query(value = " SELECT t FROM RMNCHMBeneficiaryaddress t WHERE DATE(t.createdDate) BETWEEN DATE(:fromDate) " - + " AND DATE(:toDate) AND t.createdBy = :userName ") - Page getBenDataWithinDates(@Param("userName") String userName, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate, Pageable pageable); + + @Query("SELECT t FROM RMNCHMBeneficiaryaddress t " + + "WHERE t.createdDate BETWEEN :fromDate AND :toDate " + + "AND t.createdBy = :userName") + Page getBenDataWithinDates( + @Param("userName") String userName, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate, + Pageable pageable); @Query(value = " SELECT t FROM RMNCHMBeneficiaryaddress t WHERE t.createdBy = :userName ") Page getBenDataByUser(@Param("userName") String userName, Pageable pageable); @Query(value = " SELECT t FROM RMNCHMBeneficiarymapping t WHERE t.benAddressId = :addressID") - RMNCHMBeneficiarymapping getByAddressID(@Param("addressID") BigInteger addressID); + List getByAddressID(@Param("addressID") BigInteger addressID); @Query(value = " SELECT t FROM RMNCHMBeneficiarymapping t WHERE t.benRegId = :BenRegId") RMNCHMBeneficiarymapping getById(@Param("BenRegId") BigInteger BenRegId); @@ -61,7 +72,7 @@ Page getBenDataWithinDates(@Param("userName") String u BigInteger getBenIdFromRegID(@Param("benRegID") Long benRegID); @Query(value = " SELECT t FROM RMNCHBeneficiaryDetailsRmnch t WHERE t.BenRegId =:benRegID ") - RMNCHBeneficiaryDetailsRmnch getDetailsByRegID(@Param("benRegID") Long benRegID); + List getDetailsByRegID(@Param("benRegID") Long benRegID); @Query(value = " SELECT t FROM RMNCHBornBirthDetails t WHERE t.BenRegId =:benRegID ") RMNCHBornBirthDetails getBornBirthByRegID(@Param("benRegID") Long benRegID); @@ -72,6 +83,9 @@ Page getBenDataWithinDates(@Param("userName") String u @Query(nativeQuery = true, value = " SELECT HealthIdNumber,HealthID FROM db_iemr.m_benhealthidmapping WHERE BeneficiaryRegID = :benRegId ") Object[] getBenHealthIdNumber(@Param("benRegId") BigInteger benRegId); + + @Query(nativeQuery = true, value = " SELECT HealthIdNumber,HealthID FROM db_iemr.m_benhealthidmapping WHERE HealthIdNumber = :HealthIdNumber ") + Object[] getHealthIdNumber(@Param("HealthIdNumber") String HealthIdNumber); @Query(nativeQuery = true, value = " SELECT HealthID,HealthIdNumber,isNewAbha FROM db_iemr.t_healthid WHERE HealthIdNumber = :healthIdNumber ") ArrayList getBenHealthDetails(@Param("healthIdNumber") String healthIdNumber); @@ -83,6 +97,24 @@ Page getBenDataWithinDates(@Param("userName") String u RMNCHMBeneficiarydetail findByBeneficiaryDetailsId(@Param("beneficiaryDetailsId") BigInteger beneficiaryDetailsId); - - + // BeneficiaryRepo — replaces 3 separate queries per beneficiary + @Query(value = """ + SELECT + ibd.BeneficiaryId AS benId, + bd.firstName AS firstName, + bd.lastName AS lastName + FROM db_identity.i_beneficiarydetails_rmnch ibd + JOIN db_identity.i_beneficiarymapping bm + ON bm.BenRegId = ibd.BeneficiaryRegID + JOIN db_identity.i_beneficiarydetails bd + ON bd.beneficiaryDetailsId = bm.BenDetailsId + WHERE ibd.BeneficiaryId IN :benIds + """, nativeQuery = true) + List findBenNamesByBenIds(@Param("benIds") List benIds); + +// BeneficiaryRepo — replaces the per-row getBenIdFromRegID call +@Query("SELECT b.BenRegId, b.benficieryid " + + "FROM RMNCHBeneficiaryDetailsRmnch b " + + "WHERE b.BenRegId IN :regIds AND b.benficieryid IS NOT NULL") +List getBenIdsFromRegIDs(@Param("regIds") List regIds); } diff --git a/src/main/java/com/iemr/flw/repo/identity/HouseHoldRepo.java b/src/main/java/com/iemr/flw/repo/identity/HouseHoldRepo.java index 514eeb6bd..a5ee8f258 100644 --- a/src/main/java/com/iemr/flw/repo/identity/HouseHoldRepo.java +++ b/src/main/java/com/iemr/flw/repo/identity/HouseHoldRepo.java @@ -5,8 +5,10 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.util.List; + public interface HouseHoldRepo extends JpaRepository { @Query(" SELECT t FROM RMNCHHouseHoldDetails t WHERE t.houseoldId =:houseoldId ") - RMNCHHouseHoldDetails getByHouseHoldID(@Param("houseoldId") long houseoldId); + List getByHouseHoldID(@Param("houseoldId") long houseoldId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/ANCVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/ANCVisitRepo.java index 067e6acc3..67e3e7b9d 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/ANCVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/ANCVisitRepo.java @@ -17,8 +17,13 @@ public interface ANCVisitRepo extends JpaRepository { List getANCForPW(@Param("userId") String userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query(value = "SELECT anc FROM ANCVisit anc WHERE anc.createdBy = :userId and anc.isActive = true") + List getANCForPW(@Param("userId") String userId); + @Query - ANCVisit findANCVisitByBenIdAndAncVisitAndIsActive(Long benId, Integer ancVisit, boolean b); + List findANCVisitByBenIdAndAncVisitAndIsActive(Long benId, Integer ancVisit, boolean b); + + List findByBenId(Long benId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/AncCounsellingCareRepo.java b/src/main/java/com/iemr/flw/repo/iemr/AncCounsellingCareRepo.java new file mode 100644 index 000000000..714dae596 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/AncCounsellingCareRepo.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.AncCare; +import com.iemr.flw.domain.iemr.AncCounsellingCare; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface AncCounsellingCareRepo extends JpaRepository { + List findAllByUserId(Integer userId); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java new file mode 100644 index 000000000..78bb368bf --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java @@ -0,0 +1,85 @@ +package com.iemr.flw.repo.iemr; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +import com.iemr.flw.domain.iemr.AshaSupervisorMapping; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface AshaSupervisorLoginRepo extends CrudRepository { + + ArrayList findBySupervisorUserIDAndDeletedFalse(Integer supervisorUserID); + + // API 1: All ASHAs mapped to a supervisor with facility info + @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID AND u.Deleted = false " + + "JOIN m_facility f ON f.FacilityID = asm.facilityID AND f.Deleted = false " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false", nativeQuery = true) + List getAllMappedAshas(@Param("supervisorUserID") Integer supervisorUserID); + + // API 2: ASHAs at a specific facility for a supervisor with user details + @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID " + + "AND u.Deleted = false " + + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + + "JOIN incentive_activity_record iar " + + "ON iar.asha_id = asm.ashaUserID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.facilityID = :facilityID " + + "AND asm.deleted = false " + + "AND iar.is_claimed = true " + + "AND iar.start_date >= :startDate " + + "AND iar.end_date < :endDate " + + "AND (:approvalStatus = 0 " + + "OR iar.approval_status = :approvalStatus)", + nativeQuery = true) + List getAshasAtFacility( + @Param("supervisorUserID") Integer supervisorUserID, + @Param("facilityID") Integer facilityID, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + + @Query(value = "SELECT DISTINCT asm.ashaUserID, " + + "u.FirstName, " + + "u.LastName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u " + + "ON u.UserID = asm.ashaUserID " + + "AND u.Deleted = false " + + "LEFT JOIN m_gender g " + + "ON g.GenderID = u.GenderID " + + "JOIN incentive_activity_record iar " + + "ON iar.asha_id = asm.ashaUserID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false " + + "AND iar.is_claimed = true " + + "AND iar.start_date >= :startDate " + + "AND iar.end_date < :endDate " + + "AND ( :approvalStatus = 0 " + + "OR iar.approval_status = :approvalStatus )", + nativeQuery = true) + List getAshasAtFacility( + @Param("supervisorUserID") Integer supervisorUserID, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java index b5277c19e..9cb356626 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java @@ -24,11 +24,15 @@ import com.iemr.flw.domain.iemr.BenReferDetails; +import io.swagger.v3.oas.annotations.info.License; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository public interface BenReferDetailsRepo extends JpaRepository { @@ -40,4 +44,19 @@ public interface BenReferDetailsRepo extends JpaRepository findByCreatedBy(String userName); + + @Query(value = """ + SELECT COUNT(*) + FROM db_iemr.t_benreferdetails + WHERE CreatedBy = :userName + AND MONTH(CreatedDate) = :month + AND YEAR(CreatedDate) = :year + """, nativeQuery = true) + Long countMonthlyReferrals( + @Param("userName") String userName, + @Param("month") Integer month, + @Param("year") Integer year); + } diff --git a/src/main/java/com/iemr/flw/repo/iemr/CbacIemrDetailsRepo.java b/src/main/java/com/iemr/flw/repo/iemr/CbacIemrDetailsRepo.java new file mode 100644 index 000000000..5e93dfad6 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/CbacIemrDetailsRepo.java @@ -0,0 +1,44 @@ +/* +* 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.repo.iemr; + +import com.iemr.flw.domain.iemr.CbacDetailsImer; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + + +import java.util.List; + +@Repository +public interface CbacIemrDetailsRepo extends CrudRepository { + + public CbacDetailsImer findByBeneficiaryRegIdAndVisitCode(Long beneficiaryRegId, Long visitCode); + + List findByCreatedBy(String userName); + + @Query(value = "SELECT BeneficiaryID FROM db_identity.m_beneficiaryregidmapping " + + "WHERE BenRegId = :benRegId AND Deleted = 0", nativeQuery = true) + Long getBeneficiaryId(@Param("benRegId") Long benRegId); + +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/CdrRepo.java b/src/main/java/com/iemr/flw/repo/iemr/CdrRepo.java index d5e0e7112..069362e8f 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/CdrRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/CdrRepo.java @@ -14,7 +14,5 @@ public interface CdrRepo extends JpaRepository { CDR findCDRByBenId(Long benId); - @Query(" SELECT c FROM CDR c WHERE c.createdBy = :userId and c.createdDate >= :fromDate and c.createdDate <= :toDate") - List getAllCdrByBenId(@Param("userId") String userId, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + ListfindByCreatedBy(String userName); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/ChildRegisterRepo.java b/src/main/java/com/iemr/flw/repo/iemr/ChildRegisterRepo.java index 7d10f5956..f456428b3 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/ChildRegisterRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/ChildRegisterRepo.java @@ -18,4 +18,8 @@ List getChildDetailsForUser(@Param("userId") String userId, // @Query(value = "Select * from db_identity.i_cbacdetails where beneficiaryRegId = :benRegId and createdDate = :createdDate limit 1", nativeQuery = true) ChildRegister findChildRegisterByBenIdAndCreatedDate(Long benRegId, Timestamp createdDate); + + Long countByBenId(Long benId); + + List findByBenId(Long benId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java b/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java index 9ed0943c7..99487cc2b 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java @@ -18,11 +18,34 @@ List getChildVaccinationDetails(@Param("userId") String userId ChildVaccination findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName(Long benRegId, Timestamp createdDate, String vaccine); - @Query(value = "select count(*) from db_iemr.t_childvaccinedetail1 cv left outer join db_iemr.m_immunizationservicevaccination v on " + - "cv.VaccineName = v.VaccineName where cv.beneficiaryRegId = :benRegId and v.Currentimmunizationserviceid in (1,2,3,4,5) and " + - "v.category = 'CHILD'", nativeQuery = true) + @Query(value = """ + SELECT COUNT(DISTINCT cv.VaccineName) + FROM db_iemr.t_childvaccinedetail1 cv + JOIN db_iemr.m_immunizationservicevaccination v + ON cv.VaccineName = v.VaccineName + WHERE cv.BeneficiaryRegID = :benRegId + AND v.Currentimmunizationserviceid IN (1,2,3,4,5) + AND v.category = 'CHILD' + """, nativeQuery = true) Integer getFirstYearVaccineCountForBenId(@Param("benRegId") Long benRegId); + @Query(value = """ + SELECT COUNT(DISTINCT cv.VaccineName) + FROM db_iemr.t_childvaccinedetail1 cv + WHERE cv.BeneficiaryRegID = :benRegId + AND cv.VaccineName IN ( + 'BCG Vaccine', + 'OPV-1', + 'OPV-2', + 'OPV-3', + 'Pentavalent-1', + 'Pentavalent-2', + 'Pentavalent-3', + 'Measles & Rubella (MR)-1' + ) + """, nativeQuery = true) + Integer getEligibleFirstYearVaccines(@Param("benRegId") Long benRegId); + @Query(value = "select count(*) from db_iemr.m_immunizationservicevaccination v where v.Currentimmunizationserviceid in (1,2,3,4,5) " + @@ -42,4 +65,16 @@ List getChildVaccinationDetails(@Param("userId") String userId "cv.VaccineName = v.VaccineName where cv.beneficiaryRegId = :benRegId and v.Currentimmunizationserviceid = 8 and v.VaccineName = " + "'DPT Booster-2' and v.category = 'CHILD'), 1, 0);", nativeQuery = true) Integer checkDptVaccinatedUser(@Param("benRegId") Long benRegId); + + @Query(value = """ + SELECT COUNT(DISTINCT cv.VaccineName) + FROM db_iemr.t_childvaccinedetail1 cv + WHERE cv.BeneficiaryRegID = :benRegId + AND cv.VaccineName IN ( + 'DPT Booster-1', + 'Measles & Rubella (MR)-2', + 'OPV Booster' + ) + """, nativeQuery = true) + Integer getEligibleSecondYearVaccines(@Param("benRegId") Long benRegId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/ChronicDiseaseVisitRepository.java b/src/main/java/com/iemr/flw/repo/iemr/ChronicDiseaseVisitRepository.java new file mode 100644 index 000000000..e63835a96 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/ChronicDiseaseVisitRepository.java @@ -0,0 +1,14 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.ChronicDiseaseVisitEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ChronicDiseaseVisitRepository + extends JpaRepository { + + List findByUserID(Integer ashaId); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/DeliveryOutcomeRepo.java b/src/main/java/com/iemr/flw/repo/iemr/DeliveryOutcomeRepo.java index 643d7c9ab..cf09f625d 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/DeliveryOutcomeRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/DeliveryOutcomeRepo.java @@ -16,5 +16,7 @@ public interface DeliveryOutcomeRepo extends JpaRepository getDeliveryOutcomeByAshaId(@Param("userId") String userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + List findByCreatedBy(String userName); + DeliveryOutcome findDeliveryOutcomeByBenIdAndIsActive(Long benId, Boolean isActive); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java b/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java index 567b62a53..36873319e 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java +++ b/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java @@ -16,4 +16,6 @@ public interface DiseaseLeprosyRepository extends JpaRepository getByCreatedBy(@Param("createdBy") String createdBy); + + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/EligibleCoupleRegisterRepo.java b/src/main/java/com/iemr/flw/repo/iemr/EligibleCoupleRegisterRepo.java index 2eae0b059..218c5b2b3 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/EligibleCoupleRegisterRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/EligibleCoupleRegisterRepo.java @@ -14,7 +14,12 @@ public interface EligibleCoupleRegisterRepo extends JpaRepository findByCreatedBy(String userName); + @Query(" SELECT ecr FROM EligibleCoupleRegister ecr WHERE ecr.createdBy = :userId and ecr.createdDate >= :fromDate and ecr.createdDate <= :toDate") List getECRegRecords(@Param("userId") String userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + + @Query(" SELECT ecr FROM EligibleCoupleRegister ecr WHERE ecr.createdBy = :userId") + List getECRegRecords(@Param("userId") String userId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/EmployeeMasterRepo.java b/src/main/java/com/iemr/flw/repo/iemr/EmployeeMasterRepo.java index d3ac8edfb..943b43b12 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/EmployeeMasterRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/EmployeeMasterRepo.java @@ -1,12 +1,14 @@ package com.iemr.flw.repo.iemr; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; @Repository -public interface EmployeeMasterRepo extends JpaRepository { - M_User findByUserID(Integer userID); - - M_User getUserByUserID(Integer parseLong); +public interface EmployeeMasterRepo extends JpaRepository { + @Query("SELECT u FROM User u WHERE u.userID = :userID and u.deleted=false and u.statusID in (1, 2)") + User findUserByUserID(@Param("userID") Integer userID); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/EyeCheckUpVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/EyeCheckUpVisitRepo.java index c0e3df739..fd713c445 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/EyeCheckUpVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/EyeCheckUpVisitRepo.java @@ -10,4 +10,5 @@ public interface EyeCheckUpVisitRepo extends JpaRepository { List findByUserId(Integer userId); + List findByCreatedBy(String userName); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/FacilityLoginRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FacilityLoginRepo.java new file mode 100644 index 000000000..2f956b3b3 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/FacilityLoginRepo.java @@ -0,0 +1,98 @@ +package com.iemr.flw.repo.iemr; + +import java.util.List; + +import com.iemr.flw.domain.iemr.AshaSupervisorMapping; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + + +@Repository +public interface FacilityLoginRepo extends CrudRepository { + + // Get user's facility IDs from m_UserServiceRoleMapping (for ANY user) + @Query(value = "SELECT DISTINCT usrm.FacilityID " + + "FROM m_UserServiceRoleMapping usrm " + + "WHERE usrm.UserID = :userID AND usrm.Deleted = false " + + "AND usrm.FacilityID IS NOT NULL", nativeQuery = true) + List getUserFacilityIDs(@Param("userID") Integer userID); + + // Get facility details with geo names and facilityType + @Query(value = "SELECT DISTINCT f.FacilityID, f.FacilityName, " + + "f.StateID, COALESCE(s.StateName,'') AS stateName, " + + "f.DistrictID, COALESCE(d.DistrictName,'') AS districtName, " + + "f.BlockID, COALESCE(b.BlockName,'') AS blockName, " + + "COALESCE(f.RuralUrban,'') AS ruralUrban, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName " + + "FROM m_facility f " + + "LEFT JOIN m_state s ON s.StateID = f.StateID " + + "LEFT JOIN m_district d ON d.DistrictID = f.DistrictID " + + "LEFT JOIN m_districtblock b ON b.BlockID = f.BlockID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE f.FacilityID IN :facilityIDs AND f.Deleted = false", nativeQuery = true) + List getFacilityDetails(@Param("facilityIDs") List facilityIDs); + + // ASHA login: get supervisor details + @Query(value = "SELECT asm.supervisorUserID, u.FirstName, u.LastName, u.ContactNo, " + + "COALESCE(u.EmployeeID,'') AS employeeID " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.supervisorUserID " + + "WHERE asm.ashaUserID = :ashaUserID AND asm.deleted = false " + + "AND u.Deleted = false LIMIT 1", nativeQuery = true) + List getSupervisorForAsha(@Param("ashaUserID") Integer ashaUserID); + + @Query(value = "SELECT GenderName FROM m_gender WHERE GenderID = :genderID", nativeQuery = true) + String getGenderName(@Param("genderID") Integer genderID); + + // Villages mapped to facilities + @Query(value = "SELECT fvm.FacilityID, fvm.DistrictBranchID, dbm.VillageName " + + "FROM facility_village_mapping fvm " + + "JOIN m_DistrictBranchMapping dbm ON dbm.DistrictBranchID = fvm.DistrictBranchID " + + "WHERE fvm.FacilityID IN :facilityIDs AND fvm.Deleted = false", nativeQuery = true) + List getVillagesForFacilities(@Param("facilityIDs") List facilityIDs); + + // ASHA login: get peers at same facility (ANM, CHO, etc.) + @Query(value = "SELECT DISTINCT usrm.UserID, u.FirstName, u.LastName, r.RoleName, " + + "COALESCE(u.EmployeeID,'') AS employeeID, " + + "COALESCE(u.ContactNo,'') AS mobile " + + "FROM m_UserServiceRoleMapping usrm " + + "JOIN m_User u ON u.UserID = usrm.UserID " + + "JOIN m_Role r ON r.RoleID = usrm.RoleID " + + "WHERE usrm.FacilityID IN :facilityIDs " + + "AND usrm.UserID != :currentUserID " + + "AND usrm.Deleted = false AND u.Deleted = false", nativeQuery = true) + List getPeersAtFacility(@Param("facilityIDs") List facilityIDs, + @Param("currentUserID") Integer currentUserID); + + // Supervisor: get mapped ASHAs with facility details + @Query(value = "SELECT DISTINCT u.UserID, u.FirstName, u.LastName, " + + "COALESCE(u.EmployeeID,'') AS employeeID, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName, " + + "COALESCE(u.ContactNo,'') AS mobile " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID " + + "JOIN m_facility f ON f.FacilityID = asm.facilityID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false AND u.Deleted = false AND f.Deleted = false", nativeQuery = true) + List getMappedAshasBySupervisor(@Param("supervisorUserID") Integer supervisorUserID); + + // CHO/ANM: get ASHAs at same facilities + @Query(value = "SELECT DISTINCT u.UserID, u.FirstName, u.LastName, " + + "COALESCE(u.EmployeeID,'') AS employeeID, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName, " + + "COALESCE(u.ContactNo,'') AS mobile " + + "FROM m_UserServiceRoleMapping usrm " + + "JOIN m_User u ON u.UserID = usrm.UserID " + + "JOIN m_Role r ON r.RoleID = usrm.RoleID " + + "JOIN m_facility f ON f.FacilityID = usrm.FacilityID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE usrm.FacilityID IN :facilityIDs " + + "AND r.RoleName = 'ASHA' " + + "AND usrm.Deleted = false AND u.Deleted = false AND f.Deleted = false", nativeQuery = true) + List getAshaListByFacilities(@Param("facilityIDs") List facilityIDs); +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/FilariasisCampaignRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FilariasisCampaignRepo.java new file mode 100644 index 000000000..1fe0d3e2e --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/FilariasisCampaignRepo.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.FilariasisCampaign; +import com.iemr.flw.domain.iemr.PulsePolioCampaign; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface FilariasisCampaignRepo extends JpaRepository { + Page findByUserId(Integer userId, Pageable pageable); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java index 655c05471..cbc7f568d 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java @@ -1,6 +1,8 @@ package com.iemr.flw.repo.iemr; import com.iemr.flw.domain.iemr.HbncVisit; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -20,6 +22,5 @@ public interface HbncVisitRepo extends JpaRepository { HbncVisit findByBeneficiaryIdAndVisit_day(@Param("beneficiaryId") Long beneficiaryId, @Param("visitDay") String visitDay); - List findByAshaId(Integer ashaId); - + Page findByAshaId(Integer ashaId, Pageable pageable); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IFAFormSubmissionRepository.java b/src/main/java/com/iemr/flw/repo/iemr/IFAFormSubmissionRepository.java index 40cbd60bc..0b1b5ff72 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IFAFormSubmissionRepository.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IFAFormSubmissionRepository.java @@ -2,6 +2,8 @@ import com.iemr.flw.domain.iemr.IFAFormSubmissionData; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; @@ -9,4 +11,10 @@ public interface IFAFormSubmissionRepository extends JpaRepository { List findByUserId(Integer userName); + @Query("SELECT i FROM IFAFormSubmissionData i " + + "WHERE i.userId = :userId " + + "AND i.visitDate = :visitDate") + List findTodayData( + @Param("userId") Integer userId, + @Param("visitDate") String visitDate); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveActivityLangMappingRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveActivityLangMappingRepo.java index f98070101..4ba40dc6e 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveActivityLangMappingRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveActivityLangMappingRepo.java @@ -3,9 +3,12 @@ import com.iemr.flw.domain.iemr.IncentiveActivityLangMapping; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Collection; import java.util.List; import java.util.Optional; public interface IncentiveActivityLangMappingRepo extends JpaRepository { IncentiveActivityLangMapping findByIdAndName(Long activityId,String activityName); + List findAllByIdIn(List ids); + } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentivePendingActivityRepository.java b/src/main/java/com/iemr/flw/repo/iemr/IncentivePendingActivityRepository.java new file mode 100644 index 000000000..295d447bb --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentivePendingActivityRepository.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import java.util.Optional; +import com.iemr.flw.domain.iemr.IncentivePendingActivity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + + +@Repository +public interface IncentivePendingActivityRepository extends JpaRepository { + + Optional findByMincentiveIdAndActivityId(Long mIncentiveId,Long activityId); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 6b8db13e3..8c21f0e9f 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -2,43 +2,213 @@ import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import jakarta.persistence.Column; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import java.sql.Timestamp; import java.util.List; +import java.util.Optional; @Repository public interface IncentiveRecordRepo extends JpaRepository { - @Query("select record from IncentiveActivityRecord record where record.activityId = :id and record.createdDate = :createdDate and record.benId = :benId") - IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId(@Param("id") Long id, @Param("createdDate") Timestamp createdDate, @Param("benId") Long benId); + @Query(value = """ + SELECT * + FROM db_iemr.incentive_activity_record r + WHERE r.activity_id = :id + AND r.ben_id = :benId + AND r.asha_id = :ashaId + AND MONTH(r.start_date) = MONTH(:createdDate) + AND YEAR(r.start_date) = YEAR(:createdDate) + LIMIT 1 + """, nativeQuery = true) + IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId( + @Param("id") Long id, + @Param("createdDate") Timestamp createdDate, + @Param("benId") Long benId, + @Param("ashaId") Integer ashaId); - @Query("select record from IncentiveActivityRecord record where record.activityId = :id and record.createdDate = :createdDate and record.benId = :benId and record.ashaId = :ashaId") - IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId(@Param("id") Long id, @Param("createdDate") Timestamp createdDate, @Param("benId") Long benId,@Param("ashaId") Integer ashaId); + Optional findById(Long id); - @Query("SELECT record FROM IncentiveActivityRecord record " + - "WHERE record.activityId = :id " + - "AND record.createdDate BETWEEN :startDate AND :endDate " + - "AND record.benId = :benId " + // ← space added here - "AND record.ashaId = :ashaId") + @Query(value = """ + SELECT * + FROM incentive_activity_record + WHERE activity_id = :activityId + AND ben_id = :benId + AND asha_id = :ashaId + AND created_date >= :startOfMonth + AND created_date < :startOfNextMonth + ORDER BY created_date DESC + LIMIT 1 + """, nativeQuery = true) IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId( - @Param("id") Long id, - @Param("startDate") Timestamp startDate, - @Param("endDate") Timestamp endDate, + @Param("activityId") Long activityId, @Param("benId") Long benId, - @Param("ashaId") Integer ashaId + @Param("ashaId") Integer ashaId, + @Param("startOfMonth") Timestamp startOfMonth, + @Param("startOfNextMonth") Timestamp startOfNextMonth ); @Query("select record from IncentiveActivityRecord record where record.ashaId = :ashaId and record.startDate >= :fromDate and record.startDate <= :toDate and record.endDate >= :fromDate and record.endDate <= :toDate ") - List findRecordsByAsha(@Param("ashaId") Integer ashaId, @Param("fromDate") Timestamp fromDate,@Param("toDate") Timestamp toDate); + List findRecordsByAsha(@Param("ashaId") Integer ashaId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query("SELECT DISTINCT record FROM IncentiveActivityRecord record WHERE record.ashaId = :ashaId") + Page findRecordsByAsha(@Param("ashaId") Integer ashaId, Pageable pageable); - @Query("select record from IncentiveActivityRecord record where record.ashaId = :ashaId") + @Query("SELECT DISTINCT record FROM IncentiveActivityRecord record WHERE record.ashaId = :ashaId") List findRecordsByAsha(@Param("ashaId") Integer ashaId); + + @Query("SELECT " + + "SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), " + + "SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), " + + "SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END) " + + "FROM IncentiveActivityRecord record " + + "WHERE record.ashaId = :ashaId " + + "AND record.isClaimed = true " + + "AND record.createdDate >= :startDate " + + "AND record.createdDate < :endDate") + List getStatusCountByAshaId( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + + @Query("SELECT COALESCE(SUM(record.amount), 0) " + + "FROM IncentiveActivityRecord record " + + "JOIN IncentiveActivity master ON record.activityId = master.id " + + "WHERE record.ashaId = :ashaId " + + "AND master.state = :stateCode " + + "AND record.isClaimed = true " + + "AND record.startDate >= :fromDate " + + "AND record.endDate <= :toDate " + + "AND (:approvalStatus = 0 OR record.approvalStatus = :approvalStatus)") + Long getTotalAmountByAsha( + @Param("ashaId") Integer ashaId, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate, + @Param("approvalStatus") Integer approvalStatus, + @Param("stateCode") Integer stateCode); + + + @Query("SELECT record " + + "FROM IncentiveActivityRecord record " + + "WHERE record.ashaId = :ashaId " + + "AND record.isClaimed = true " + + "AND record.startDate <= :toDate " + + "AND record.endDate >= :fromDate") + List getRecordsByAsha( + @Param("ashaId") Integer ashaId, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate); + + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.approvalStatus = :approvalStatus, " + + "iar.verifiedByUserId = :ashaSupervisorUserId, " + + "iar.reason = NULL, " + + "iar.otherReason = NULL, " + + "iar.approvalDate = :approvalDate, " + + "iar.verifiedByUserName = :ashaSupervisorUserName " + + "WHERE iar.ashaId = :ashaId " + + "AND iar.isClaimed = true " + + "AND iar.createdDate >= :startDate " + + "AND iar.createdDate < :endDate") + int updateApprovalStatusByAshaAndDateRange( + @Param("ashaId") Integer ashaId, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate, + @Param("approvalDate") Timestamp approvalDate, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName); + + + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.approvalStatus = :status, " + + "iar.verifiedByUserId = :ashaSupervisorUserId, " + + "iar.reason = :reason, " + + "iar.otherReason = :otherReason, " + + "iar.approvalDate = :approvalDate, " + + "iar.verifiedByUserName = :ashaSupervisorUserName " + + "WHERE iar.isClaimed = true") + int updateApprovalStatusById( + @Param("status") Integer status, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName, + @Param("reason") String reason, + @Param("approvalDate") Timestamp approvalDate, + @Param("otherReason") String otherReason + ); + + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.isClaimed = :isClaimed, " + + "iar.calimedDate = :calimedDate, " + + "iar.approvalStatus = 102 " + + "WHERE iar.ashaId = :ashaId " + + "AND iar.createdDate >= :startDate " + + "AND iar.createdDate < :endDate") + int updateClaimStatusByAshaAndDateRange( + @Param("ashaId") Integer ashaId, + @Param("isClaimed") Boolean isClaimed, + @Param("calimedDate") Timestamp calimedDate, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate + ); + + @Query("SELECT DISTINCT iar.ashaId FROM IncentiveActivityRecord iar " + + "WHERE iar.calimedDate >= :startDate " + + "AND iar.calimedDate < :endDate " + + "AND iar.isClaimed = true " + + "AND iar.approvalStatus = 101") + List findDistinctAshaIdsByDateRange( + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate + ); + + @Query("SELECT iar FROM IncentiveActivityRecord iar " + + "WHERE iar.ashaId = :ashaId " + + "AND iar.calimedDate >= :startDate " + + "AND iar.calimedDate < :endDate " + + "AND iar.isClaimed = true " + + "AND iar.approvalStatus = 101") + List findClaimedApprovedRecordsByAshaAndDateRange( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate + ); + + // RecordRepo — existing records batch mein fetch karo + @Query("SELECT r FROM IncentiveActivityRecord r " + + "WHERE r.activityId = :activityId " + + "AND r.benId IN :benIds " + + "AND r.ashaId = :ashaId") + List findExistingRecords( + @Param("activityId") Long activityId, + @Param("benIds") List benIds, + @Param("ashaId") Integer ashaId + ); + + @Query("SELECT r FROM IncentiveActivityRecord r WHERE r.ashaId = :ashaId " + + "AND r.calimedDate >= :startDate AND r.calimedDate < :endDate " + + "AND (:approvalStatus = 0 OR r.approvalStatus = :approvalStatus)") + List getRecordsBySuperVisor( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate, + @Param("approvalStatus") Integer approvalStatus); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentivesRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentivesRepo.java index 112f74ef5..d1cbc7f84 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentivesRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentivesRepo.java @@ -9,7 +9,9 @@ import org.springframework.stereotype.Repository; import java.sql.Timestamp; +import java.util.Collection; import java.util.List; +import java.util.Set; @Repository public interface IncentivesRepo extends JpaRepository { @@ -28,4 +30,28 @@ IncentiveActivity findIncentiveMasterById( @Query("select record from IncentiveActivityRecord record where record.activityId = :id and record.createdDate = :createdDate and record.benId = :benId") IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId(@Param("id") Long id, @Param("createdDate") Timestamp createdDate, @Param("benId") Long benId); -} + + @Query(value = "SELECT " + + "SUM(CASE WHEN i.approval_status = 101 THEN 1 ELSE 0 END) as pendingCount, " + + "SUM(CASE WHEN i.approval_status = 102 THEN 1 ELSE 0 END) as approvalCount, " + + "SUM(CASE WHEN i.approval_status = 103 THEN 1 ELSE 0 END) as rejectCount " + + "FROM m_incentive_activity i " + + "WHERE i.asha_id = :ashaId " + + "AND i.is_deleted = false", + nativeQuery = true) + Object[] getStatusCountByAshaId(@Param("ashaId") Integer ashaId); + + List findByGroupAndIsDeleted(String group, Boolean isDeleted); + + List findByGroupNotAndIsDeleted(String group, Boolean isDeleted); + + // IncentivesRepo — replaces N calls to findIncentiveMasterById() + @Query("SELECT i.id FROM IncentiveActivity i WHERE i.id IN :ids AND i.isDeleted = false AND " + + "(:isCG = true AND i.group = 'ACTIVITY' OR :isCG = false AND i.group != 'ACTIVITY')") + Set findValidActivityIds(@Param("ids") List ids, @Param("isCG") boolean isCG); + + @Query("SELECT i FROM IncentiveActivity i WHERE i.name IN :names AND i.group = :groupName") + List findIncentiveMasterByNameAndGroup( + @Param("names") List names, + @Param("groupName") String groupName + );} diff --git a/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java b/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java index 4227fb3a2..a2b38f555 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java +++ b/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java @@ -12,7 +12,7 @@ @Repository public interface LeprosyFollowUpRepository extends JpaRepository { - Optional findByBenId(Long benId); + List findByBenId(Long benId); // Custom queries can be added here if needed @Query("SELECT s FROM LeprosyFollowUp s WHERE s.createdBy = :createdBy") diff --git a/src/main/java/com/iemr/flw/repo/iemr/MdsrRepo.java b/src/main/java/com/iemr/flw/repo/iemr/MdsrRepo.java index 532a62c91..127954c6f 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/MdsrRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/MdsrRepo.java @@ -14,7 +14,6 @@ public interface MdsrRepo extends JpaRepository { MDSR findMDSRByBenId(Long benId); - @Query(" SELECT m FROM MDSR m WHERE m.createdBy = :userId and m.createdDate >= :fromDate and m.createdDate <= :toDate") - List getAllMdsrByAshaId(@Param("userId") String userId, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + List findByCreatedBy(String userName); + } diff --git a/src/main/java/com/iemr/flw/repo/iemr/OrsCampaignRepo.java b/src/main/java/com/iemr/flw/repo/iemr/OrsCampaignRepo.java new file mode 100644 index 000000000..fbbe380bb --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/OrsCampaignRepo.java @@ -0,0 +1,17 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.CampaignOrs; +import com.iemr.flw.dto.iemr.OrsCampaignDTO; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface OrsCampaignRepo extends JpaRepository { + Page findByUserId(Integer userId, Pageable pageable); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/PNCVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/PNCVisitRepo.java index 063a0795a..39da97da4 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/PNCVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/PNCVisitRepo.java @@ -12,9 +12,10 @@ @Repository public interface PNCVisitRepo extends JpaRepository { - @Query(value = "SELECT pnc FROM PNCVisit pnc WHERE pnc.createdBy = :userId and pnc.isActive = true and pnc.createdDate >= :fromDate and pnc.createdDate <= :toDate") - List getPNCForPW(@Param("userId") String userId, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query(value = "SELECT pnc FROM PNCVisit pnc WHERE pnc.createdBy = :userId and pnc.isActive = true") + List getPNCForPW(@Param("userId") String userId); PNCVisit findPNCVisitByBenIdAndPncPeriodAndIsActive(Long benId, Integer pncVisit, Boolean isActive); + + List findByBenId(Long benId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/PulsePolioCampaignRepo.java b/src/main/java/com/iemr/flw/repo/iemr/PulsePolioCampaignRepo.java new file mode 100644 index 000000000..c2cded971 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/PulsePolioCampaignRepo.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.CampaignOrs; +import com.iemr.flw.domain.iemr.PulsePolioCampaign; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PulsePolioCampaignRepo extends JpaRepository { + Page findByUserId(Integer userId, Pageable pageable); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java new file mode 100644 index 000000000..a56587776 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -0,0 +1,111 @@ +package com.iemr.flw.repo.iemr; + +import java.sql.Timestamp; +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; + +@Repository +public interface SupervisorDashboardRepo extends JpaRepository { + + // Get all ASHA userIDs mapped to a supervisor + @Query(value = "SELECT DISTINCT asm.ashaUserID " + + "FROM asha_supervisor_mapping asm " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false", nativeQuery = true) + List getAshaIdsBySupervisor(@Param("supervisorUserID") Integer supervisorUserID); + + // Get ASHAs with facility info for a supervisor + @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID AND u.Deleted = false " + + "JOIN m_facility f ON f.FacilityID = asm.facilityID AND f.Deleted = false " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false", nativeQuery = true) + List getAshasWithFacilityInfo(@Param("supervisorUserID") Integer supervisorUserID); + + // Unclaimed incentive count per ASHA + @Query(value = "SELECT iar.asha_id, " + + "COUNT(*) AS unclaimedCount " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN (:ashaIds) " + + "AND iar.created_date >= :startDate " + + "AND iar.created_date < :endDate " + + "AND (iar.is_claimed = false OR iar.is_claimed IS NULL) " + + "GROUP BY iar.asha_id", + nativeQuery = true) + List getUnclaimedCountByAshaIds( + @Param("ashaIds") List ashaIds, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + // Get facility details with geo names + @Query(value = "SELECT DISTINCT f.FacilityID, f.FacilityName, " + + "COALESCE(s.StateName,'') AS stateName, " + + "COALESCE(d.DistrictName,'') AS districtName, " + + "COALESCE(b.BlockName,'') AS blockName, " + + "COALESCE(f.RuralUrban,'') AS ruralUrban, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName " + + "FROM m_facility f " + + "LEFT JOIN m_state s ON s.StateID = f.StateID " + + "LEFT JOIN m_district d ON d.DistrictID = f.DistrictID " + + "LEFT JOIN m_districtblock b ON b.BlockID = f.BlockID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE f.FacilityID IN :facilityIDs AND f.Deleted = false", nativeQuery = true) + List getFacilityDetails(@Param("facilityIDs") List facilityIDs); + + // Villages mapped to facilities + @Query(value = "SELECT fvm.FacilityID, fvm.DistrictBranchID, dbm.VillageName " + + "FROM facility_village_mapping fvm " + + "JOIN m_DistrictBranchMapping dbm ON dbm.DistrictBranchID = fvm.DistrictBranchID " + + "WHERE fvm.FacilityID IN :facilityIDs AND fvm.Deleted = false", nativeQuery = true) + List getVillagesForFacilities(@Param("facilityIDs") List facilityIDs); + + // Incentive status counts per ASHA: verified, rejected, pending, total amount + @Query(value = "SELECT iar.asha_id, " + + "COUNT(*) AS totalRecords, " + + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " + + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " + + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN (:ashaIds) " + + "AND iar.created_date >= :startDate " + + "AND iar.is_claimed = true " + + "AND iar.created_date < :endDate " + + "GROUP BY iar.asha_id", + nativeQuery = true) + List getIncentiveStatusByAshaIds( + @Param("ashaIds") List ashaIds, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + // Incentive activity history per ASHA (recent records) + @Query(value = "SELECT iar.asha_id, iar.name AS activityName, " + + "iar.amount, iar.is_eligible, iar.created_date " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN :ashaIds " + + "ORDER BY iar.created_date DESC", nativeQuery = true) + List getIncentiveHistoryByAshaIds(@Param("ashaIds") List ashaIds); + + // Supervisor user details + @Query(value = "SELECT u.UserID, u.FirstName, u.LastName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM m_User u " + + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + + "WHERE u.UserID = :userId AND u.Deleted = false", nativeQuery = true) + List getSupervisorUserDetails(@Param("userId") Integer userId); +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/TBConfirmedTreatmentRepository.java b/src/main/java/com/iemr/flw/repo/iemr/TBConfirmedTreatmentRepository.java new file mode 100644 index 000000000..31345dd40 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/TBConfirmedTreatmentRepository.java @@ -0,0 +1,17 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.TBConfirmedCase; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface TBConfirmedTreatmentRepository + extends JpaRepository { + + List findByBenId(Long benId); + List findByUserId(Integer benId); + +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java b/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java index e2f7fed00..61be2a57e 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java @@ -15,6 +15,6 @@ public interface TBScreeningRepo extends JpaRepository { @Query(value = "SELECT tbs FROM TBScreening tbs WHERE tbs.benId = :benId and tbs.userId = :userId") TBScreening getByUserIdAndBenId(@Param("benId") Long benId, @Param("userId") Integer userId); - @Query(value = "SELECT tbs FROM TBScreening tbs WHERE tbs.userId = :userId and tbs.visitDate >= :fromDate and tbs.visitDate <= :toDate") - List getByUserId(@Param("userId") Integer userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query(value = "SELECT tbs FROM TBScreening tbs WHERE tbs.userId = :userId") + List getByUserId(@Param("userId") Integer userId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java index 899a7ffd4..2b78b68f7 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java @@ -18,10 +18,22 @@ public interface UserServiceRoleRepo extends JpaRepository getUserRole(@Param("userId") Integer userId); - @Query("select u.userId from UserServiceRole u where u.userName = :userName and u.userServciceRoleDeleted = false") + @Query(value = """ + SELECT UserID + FROM db_iemr.v_userservicerolemapping + WHERE UserName = :userName + AND UserServciceRoleDeleted = 0 + LIMIT 1 + """, nativeQuery = true) Integer getUserIdByName(@Param("userName") String userName); - @Query("select u.userName from UserServiceRole u where u.userId = :userId and u.userServciceRoleDeleted = false") - String getUserNamedByUserId(@Param("userId") Integer userId); + @Query(value = """ + SELECT UserName + FROM db_iemr.v_userservicerolemapping + WHERE UserID = :userId + AND UserServciceRoleDeleted = 0 + LIMIT 1 + """, nativeQuery = true) + String getUserNamedByUserId(@Param("userId") Integer userId); } diff --git a/src/main/java/com/iemr/flw/service/AbhaBeneficiaryService.java b/src/main/java/com/iemr/flw/service/AbhaBeneficiaryService.java new file mode 100644 index 000000000..02a1281b5 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/AbhaBeneficiaryService.java @@ -0,0 +1,12 @@ +package com.iemr.flw.service; + +import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; +import com.iemr.flw.dto.iemr.AbhaRequestDTO; +import org.springframework.stereotype.Service; + +import java.util.List; + +public interface AbhaBeneficiaryService { + + Object getBeneficiaryByAbha(AbhaRequestDTO request); +} diff --git a/src/main/java/com/iemr/flw/service/AbhaTokenService.java b/src/main/java/com/iemr/flw/service/AbhaTokenService.java new file mode 100644 index 000000000..dc0affaef --- /dev/null +++ b/src/main/java/com/iemr/flw/service/AbhaTokenService.java @@ -0,0 +1,7 @@ +package com.iemr.flw.service; + +import java.util.Map; + +public interface AbhaTokenService { + Map getAbhaToken() throws Exception; +} diff --git a/src/main/java/com/iemr/flw/service/BeneficiaryService.java b/src/main/java/com/iemr/flw/service/BeneficiaryService.java index 1db3026b9..e69bc887f 100644 --- a/src/main/java/com/iemr/flw/service/BeneficiaryService.java +++ b/src/main/java/com/iemr/flw/service/BeneficiaryService.java @@ -10,7 +10,7 @@ public interface BeneficiaryService { String getBenData(GetBenRequestHandler requestDTO, String authorisation) throws Exception; - String saveEyeCheckupVsit(List eyeCheckupRequestDTOS); + String saveEyeCheckupVsit(List eyeCheckupRequestDTOS,String token); - List getEyeCheckUpVisit(GetBenRequestHandler request); + List getEyeCheckUpVisit(GetBenRequestHandler request,String token); } diff --git a/src/main/java/com/iemr/flw/service/CampaignService.java b/src/main/java/com/iemr/flw/service/CampaignService.java new file mode 100644 index 000000000..26c67a6ac --- /dev/null +++ b/src/main/java/com/iemr/flw/service/CampaignService.java @@ -0,0 +1,24 @@ +package com.iemr.flw.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.iemr.flw.domain.iemr.CampaignOrs; +import com.iemr.flw.domain.iemr.FilariasisCampaign; +import com.iemr.flw.domain.iemr.PulsePolioCampaign; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.utils.exception.IEMRException; + +import java.util.List; + +public interface CampaignService { + List saveOrsCampaign(List orsCampaignDTO, String token) throws IEMRException, JsonProcessingException; + + List savePolioCampaign(List polioCampaignDTOS, String token) throws IEMRException, JsonProcessingException; + + List getOrsCampaign(String token) throws IEMRException; + + List getPolioCampaign(String token) throws IEMRException; + + List saveFilariasisCampaign(List filariasisCampaignDTOS, String token) throws IEMRException, JsonProcessingException; + + List getAllFilariasisCampaign(String token) throws IEMRException; +} diff --git a/src/main/java/com/iemr/flw/service/ChildCareService.java b/src/main/java/com/iemr/flw/service/ChildCareService.java index bbd5c96f2..c78de3fdc 100644 --- a/src/main/java/com/iemr/flw/service/ChildCareService.java +++ b/src/main/java/com/iemr/flw/service/ChildCareService.java @@ -15,7 +15,7 @@ public interface ChildCareService { List getHBNCDetails(GetBenRequestHandler dto); - String saveHBNCDetails(List hbncRequestDTOs); + String saveHBNCDetails(List hbncRequestDTOs,Integer userId); List getChildVaccinationDetails(GetBenRequestHandler dto); @@ -23,7 +23,7 @@ public interface ChildCareService { List getAllChildVaccines(String category); - String saveSamDetails(List samRequest); + String saveSamDetails(List samRequest,Integer userId,String userName); List getSamVisitsByBeneficiary(GetBenRequestHandler dto); @@ -31,7 +31,7 @@ public interface ChildCareService { List getOrdDistrubtion(GetBenRequestHandler request); - List saveAllIfa(List dtoList); + List saveAllIfa(List dtoList,Integer userId); List getByBeneficiaryId(GetBenRequestHandler request); diff --git a/src/main/java/com/iemr/flw/service/DiseaseControlService.java b/src/main/java/com/iemr/flw/service/DiseaseControlService.java index 92accf4aa..65e315dce 100644 --- a/src/main/java/com/iemr/flw/service/DiseaseControlService.java +++ b/src/main/java/com/iemr/flw/service/DiseaseControlService.java @@ -24,7 +24,9 @@ */ package com.iemr.flw.service; +import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.utils.exception.IEMRException; import java.util.List; @@ -44,4 +46,7 @@ public interface DiseaseControlService { public String saveLeprosyFollowUp(LeprosyFollowUpDTO leprosyDTO); List getAllLeprosyFollowUpData(String createdBy); + List saveChronicDiseaseVisit(List requestList,String token) throws IEMRException; + + List getCdtfVisits(GetBenRequestHandler getBenRequestHandler); } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/EmployeeMasterInter.java b/src/main/java/com/iemr/flw/service/EmployeeMasterInter.java index 1c4369dac..4e81445ce 100644 --- a/src/main/java/com/iemr/flw/service/EmployeeMasterInter.java +++ b/src/main/java/com/iemr/flw/service/EmployeeMasterInter.java @@ -1,13 +1,13 @@ package com.iemr.flw.service; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; import org.springframework.stereotype.Service; import java.util.List; @Service public interface EmployeeMasterInter { - public M_User getUserDetails(Integer userID); + public User getUserDetails(Integer userID); - List getAllUsers(); + List getAllUsers(); } diff --git a/src/main/java/com/iemr/flw/service/IFAFormSubmissionService.java b/src/main/java/com/iemr/flw/service/IFAFormSubmissionService.java index 1ecd338d1..d94fbd682 100644 --- a/src/main/java/com/iemr/flw/service/IFAFormSubmissionService.java +++ b/src/main/java/com/iemr/flw/service/IFAFormSubmissionService.java @@ -9,6 +9,6 @@ import java.util.List; @Service public interface IFAFormSubmissionService { - String saveFormData(List requests); + String saveFormData(List requests,Integer userId); List getFormData(GetBenRequestHandler getBenRequestHandler); } diff --git a/src/main/java/com/iemr/flw/service/IRSRoundService.java b/src/main/java/com/iemr/flw/service/IRSRoundService.java index d45cd621a..438702d5f 100644 --- a/src/main/java/com/iemr/flw/service/IRSRoundService.java +++ b/src/main/java/com/iemr/flw/service/IRSRoundService.java @@ -8,7 +8,7 @@ @Service public interface IRSRoundService { - List addRounds(List dtos); + List addRounds(List dtos,Integer userId,String userName); List getRounds(Long householdId); } diff --git a/src/main/java/com/iemr/flw/service/IncentiveLogicService.java b/src/main/java/com/iemr/flw/service/IncentiveLogicService.java new file mode 100644 index 000000000..8becce199 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/IncentiveLogicService.java @@ -0,0 +1,35 @@ +package com.iemr.flw.service; + +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.util.Date; + +public interface IncentiveLogicService { + public IncentiveActivityRecord incentiveForLeprosyPaucibacillaryConfirmed(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + public IncentiveActivityRecord incentiveForIdentificationLeprosy(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + public IncentiveActivityRecord incentiveForLeprosyMultibacillaryConfirmed(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + + public IncentiveActivityRecord incentiveForVhndMeeting(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + + public IncentiveActivityRecord incentiveForClusterMeeting(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + public IncentiveActivityRecord incentiveForAttendingVhsnc(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForChildBirthGap(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForSecondChildGap(Long benId, Timestamp secondChildDob, Timestamp secondChildDob1, Integer userId); + + IncentiveActivityRecord incentiveForEyeSurgeyReferGovtHospital(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + IncentiveActivityRecord incentiveForEyeSurgeyReferPrivateHospital(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForMalariaFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForTbFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForTbFollowUpIsDrTb(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForGiveingIFA(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForTbSuspected(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); +} diff --git a/src/main/java/com/iemr/flw/service/IncentiveService.java b/src/main/java/com/iemr/flw/service/IncentiveService.java index ab49a0cd4..8b2e46001 100644 --- a/src/main/java/com/iemr/flw/service/IncentiveService.java +++ b/src/main/java/com/iemr/flw/service/IncentiveService.java @@ -3,6 +3,7 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.IncentiveActivityDTO; import com.iemr.flw.dto.iemr.IncentiveRequestDTO; +import com.iemr.flw.dto.iemr.PendingActivityDTO; import java.util.List; @@ -13,4 +14,12 @@ public interface IncentiveService { String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO); String getAllIncentivesByUserId(GetBenRequestHandler requestDTO); -} + String getAllIncentivesGroupedSummary(GetBenRequestHandler requestDTO); + String getAllIncentivesGroupedActivity(GetBenRequestHandler requestDTO); + + String updateIncentive(PendingActivityDTO pendingActivityDTO); + public String updateClaimStatus(Integer ashaId, + Integer month, + Integer year, + Boolean isClaimed, + String token);} diff --git a/src/main/java/com/iemr/flw/service/MaaMeetingService.java b/src/main/java/com/iemr/flw/service/MaaMeetingService.java index d5f4c5bdf..cfe6aa204 100644 --- a/src/main/java/com/iemr/flw/service/MaaMeetingService.java +++ b/src/main/java/com/iemr/flw/service/MaaMeetingService.java @@ -3,28 +3,20 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.iemr.flw.domain.iemr.IncentiveActivity; -import com.iemr.flw.domain.iemr.IncentiveActivityRecord; -import com.iemr.flw.domain.iemr.MaaMeeting; -import com.iemr.flw.domain.iemr.UwinSession; +import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.MaaMeetingRequestDTO; import com.iemr.flw.dto.iemr.MaaMeetingResponseDTO; import com.iemr.flw.masterEnum.GroupName; -import com.iemr.flw.repo.iemr.IncentiveRecordRepo; -import com.iemr.flw.repo.iemr.IncentivesRepo; -import com.iemr.flw.repo.iemr.MaaMeetingRepository; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import com.iemr.flw.repo.iemr.*; +import jakarta.persistence.EntityNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; @Service @@ -40,6 +32,9 @@ public class MaaMeetingService { private final MaaMeetingRepository repository; private final ObjectMapper objectMapper; + @Autowired + private IncentivePendingActivityRepository incentivePendingActivityRepository; + public MaaMeetingService(MaaMeetingRepository repository, ObjectMapper objectMapper) { this.repository = repository; this.objectMapper = objectMapper; @@ -51,6 +46,11 @@ public MaaMeeting saveMeeting(MaaMeetingRequestDTO req) throws Exception { meeting.setPlace(req.getPlace()); meeting.setParticipants(req.getParticipants()); meeting.setAshaId(req.getAshaId()); + meeting.setNoOfLactingMother(req.getNoOfLactingMother()); + meeting.setNoOfPragnentWomen(req.getNoOfPragnentWomen()); + meeting.setVillageName(req.getVillageName()); + meeting.setMitaninActivityCheckList(req.getMitaninActivityCheckList()); + meeting.setCreatedBy(req.getCreatedBY()); // Convert meeting images to Base64 JSON @@ -69,12 +69,93 @@ public MaaMeeting saveMeeting(MaaMeetingRequestDTO req) throws Exception { String imagesJson = objectMapper.writeValueAsString(base64Images); meeting.setMeetingImagesJson(imagesJson); } + checkAndAddIncentive(meeting); return repository.save(meeting); } + public MaaMeeting updateMeeting(MaaMeetingRequestDTO req) throws JsonProcessingException { + MaaMeeting existingMeeting = repository.findById(req.getId()) + .orElseThrow(() -> new EntityNotFoundException("Meeting not found: " + req.getId())); + + // ✅ NULL CHECK + if (req.getMeetingDate() != null) { + existingMeeting.setMeetingDate(req.getMeetingDate()); + } + if (req.getPlace() != null) { + existingMeeting.setPlace(req.getPlace()); + } + if (req.getParticipants() != null) { + existingMeeting.setParticipants(req.getParticipants()); + } + if (req.getAshaId() != null) { + existingMeeting.setAshaId(req.getAshaId()); + } + if (req.getCreatedBY() != null) { // ✅ Typo fixed: CreatedBY → CreatedBy + existingMeeting.setCreatedBy(req.getCreatedBY()); + } + + // Images - only if provided + if (req.getMeetingImages() != null && req.getMeetingImages().length > 0) { + List base64Images = Arrays.stream(req.getMeetingImages()) + .filter(file -> file != null && !file.isEmpty()) + .map(this::convertToBase64) + .collect(Collectors.toList()); + existingMeeting.setMeetingImagesJson(objectMapper.writeValueAsString(base64Images)); + } + + checkAndAddIncentive(existingMeeting); + + return repository.save(existingMeeting); + } + + public MaaMeeting updateMeetingFromFileUpload(MaaMeetingRequestDTO req, Long incentiveRecordId) throws JsonProcessingException { + MaaMeeting existingMeeting = repository.findById(req.getId()) + .orElseThrow(() -> new EntityNotFoundException("Meeting not found: " + req.getId())); + + // ✅ NULL CHECK + if (req.getMeetingDate() != null) { + existingMeeting.setMeetingDate(req.getMeetingDate()); + } + if (req.getPlace() != null) { + existingMeeting.setPlace(req.getPlace()); + } + if (req.getParticipants() != null) { + existingMeeting.setParticipants(req.getParticipants()); + } + if (req.getAshaId() != null) { + existingMeeting.setAshaId(req.getAshaId()); + } + if (req.getCreatedBY() != null) { // ✅ Typo fixed: CreatedBY → CreatedBy + existingMeeting.setCreatedBy(req.getCreatedBY()); + } + + // Images - only if provided + if (req.getMeetingImages() != null && req.getMeetingImages().length > 0) { + List base64Images = Arrays.stream(req.getMeetingImages()) + .filter(file -> file != null && !file.isEmpty()) + .map(this::convertToBase64) + .collect(Collectors.toList()); + existingMeeting.setMeetingImagesJson(objectMapper.writeValueAsString(base64Images)); + } + + if (existingMeeting.getMeetingImagesJson() != null) { + checkAndUpdateIncentive(incentiveRecordId); + + } + return repository.save(existingMeeting); + } + + + private String convertToBase64(MultipartFile file) { + try { + return Base64.getEncoder().encodeToString(file.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Failed to convert image to Base64: " + file.getOriginalFilename(), e); + } + } public List getAllMeetings(GetBenRequestHandler getBenRequestHandler) throws Exception { @@ -87,13 +168,18 @@ public List getAllMeetings(GetBenRequestHandler getBenReq dto.setPlace(meeting.getPlace()); dto.setParticipants(meeting.getParticipants()); dto.setAshaId(meeting.getAshaId()); + dto.setVillageName(meeting.getVillageName()); + dto.setNoOfLactingMother(String.valueOf(meeting.getNoOfLactingMother())); + dto.setNoOfPragnentWomen(String.valueOf(meeting.getNoOfPragnentWomen())); + dto.setMitaninActivityCheckList(meeting.getMitaninActivityCheckList()); dto.setCreatedBy(meeting.getCreatedBy()); try { if (meeting.getMeetingImagesJson() != null) { List base64Images = objectMapper.readValue( meeting.getMeetingImagesJson(), - new TypeReference>() {} + new TypeReference>() { + } ); dto.setMeetingImages(base64Images); @@ -107,22 +193,39 @@ public List getAllMeetings(GetBenRequestHandler getBenReq return dto; }).collect(Collectors.toList()); } + + private void updatePendingActivity(Integer userId, Long recordId, Long activityId, Long mIncentiveId) { + IncentivePendingActivity incentivePendingActivity = new IncentivePendingActivity(); + incentivePendingActivity.setActivityId(activityId); + incentivePendingActivity.setRecordId(recordId); + incentivePendingActivity.setUserId(userId); + incentivePendingActivity.setMincentiveId(mIncentiveId); + if (incentivePendingActivity != null) { + incentivePendingActivityRepository.save(incentivePendingActivity); + } + + } + + private void checkAndUpdateIncentive(Long incentiveId) { + updateIncentive(incentiveId); + } + private void checkAndAddIncentive(MaaMeeting meeting) { IncentiveActivity incentiveActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MAA_QUARTERLY_MEETING", GroupName.CHILD_HEALTH.getDisplayName()); IncentiveActivity incentiveActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("MAA_QUARTERLY_MEETING", GroupName.ACTIVITY.getDisplayName()); - if(incentiveActivityAM!=null){ - addIncentive(incentiveActivityAM,meeting); - } - if(incentiveActivityCH!=null){ - addIncentive(incentiveActivityCH,meeting); + if (incentiveActivityAM != null) { + addIncentive(incentiveActivityAM, meeting); + } + if (incentiveActivityCH != null) { + addIncentive(incentiveActivityCH, meeting); - } + } } - private void addIncentive(IncentiveActivity incentiveActivity,MaaMeeting meeting){ + private void addIncentive(IncentiveActivity incentiveActivity, MaaMeeting meeting) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), Timestamp.valueOf(meeting.getMeetingDate().atStartOfDay()), 0L,meeting.getAshaId()); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), Timestamp.valueOf(meeting.getMeetingDate().atStartOfDay()), 0L, meeting.getAshaId()); if (record == null) { record = new IncentiveActivityRecord(); @@ -136,9 +239,37 @@ record = new IncentiveActivityRecord(); record.setBenId(0L); record.setAshaId(meeting.getAshaId()); record.setAmount(Long.valueOf(incentiveActivity.getRate())); + record.setIsEligible(true); recordRepo.save(record); + + +// if (meeting.getMeetingImagesJson() != null) { +// record.setIsEligible(true); +// recordRepo.save(record); +// +// } else { +// record.setIsEligible(false); +// IncentiveActivityRecord activityRecord = recordRepo.save(record); +// if (activityRecord != null) { +// updatePendingActivity(meeting.getAshaId(), meeting.getId(), activityRecord.getId(), incentiveActivity.getId()); +// +// } +// +// } } } + private void updateIncentive(Long id) { + + Optional optionalRecord = recordRepo.findById(id); + + if (optionalRecord.isPresent()) { + IncentiveActivityRecord record = optionalRecord.get(); + record.setIsEligible(true); + recordRepo.save(record); + } + } + + } diff --git a/src/main/java/com/iemr/flw/service/MalariaFollowUpService.java b/src/main/java/com/iemr/flw/service/MalariaFollowUpService.java index eb979318d..324c6cd6a 100644 --- a/src/main/java/com/iemr/flw/service/MalariaFollowUpService.java +++ b/src/main/java/com/iemr/flw/service/MalariaFollowUpService.java @@ -9,7 +9,7 @@ public interface MalariaFollowUpService { - public Boolean saveFollowUp(MalariaFollowUpDTO dto) ; + public Boolean saveFollowUp(MalariaFollowUpDTO dto,String token) ; List getByUserId(Integer userId); diff --git a/src/main/java/com/iemr/flw/service/MaternalHealthService.java b/src/main/java/com/iemr/flw/service/MaternalHealthService.java index c4af27685..5e4e9b615 100644 --- a/src/main/java/com/iemr/flw/service/MaternalHealthService.java +++ b/src/main/java/com/iemr/flw/service/MaternalHealthService.java @@ -2,6 +2,7 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.utils.exception.IEMRException; import org.springframework.stereotype.Component; import java.util.List; @@ -15,7 +16,7 @@ public interface MaternalHealthService { List getANCVisits(GetBenRequestHandler dto); - String saveANCVisit(List ancVisitDTOs); + String saveANCVisit(List ancVisitDTOs,Integer useId ); List getPmsmaRecords(GetBenRequestHandler dto); @@ -25,4 +26,7 @@ public interface MaternalHealthService { String savePNCVisit(List pncVisitDTOs); + String saveANCVisitQuestions(List ancVisitQuestionsDTOS, String authorization) throws IEMRException; + + List getANCCounselling(GetBenRequestHandler requestDTO); } diff --git a/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java b/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java new file mode 100644 index 000000000..bc580a26d --- /dev/null +++ b/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java @@ -0,0 +1,20 @@ +package com.iemr.flw.service; + +import java.util.List; +import java.util.Map; + +public interface SupervisorDashboardService { + + String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year); + + Map getAshasAtFacility(Integer supervisorId, Integer facilityId, Integer month, Integer year, Integer approvalStatusID); + + public int updateApprovalStatus(Integer ashaId, + Integer month, + Integer year, + Integer approvalStatus, + String incentiveIds, + String reason, + String otherReason, + String token); +} diff --git a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java new file mode 100644 index 000000000..64505b791 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java @@ -0,0 +1,16 @@ +package com.iemr.flw.service; + +import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public interface TBConfirmedCaseService { + + String save(List tbConfirmedCaseDTO, String token) throws Exception; + + String getByBenId(Long benId, String authorisation) throws Exception; + + String getByUserId(String authorisation) throws Exception; +} diff --git a/src/main/java/com/iemr/flw/service/UwinSessionService.java b/src/main/java/com/iemr/flw/service/UwinSessionService.java index 3f6ddf0ac..ce4185c35 100644 --- a/src/main/java/com/iemr/flw/service/UwinSessionService.java +++ b/src/main/java/com/iemr/flw/service/UwinSessionService.java @@ -1,5 +1,6 @@ package com.iemr.flw.service; +import com.iemr.flw.domain.iemr.UwinSession; import com.iemr.flw.dto.iemr.UwinSessionRequestDTO; import com.iemr.flw.dto.iemr.UwinSessionResponseDTO; @@ -7,5 +8,6 @@ public interface UwinSessionService { UwinSessionResponseDTO saveSession(UwinSessionRequestDTO req) throws Exception; + UwinSession updateSession(UwinSessionRequestDTO req, Long recordId,Long activityId) throws Exception; List getSessionsByAsha(Integer ashaId) throws Exception; } diff --git a/src/main/java/com/iemr/flw/service/health/HealthService.java b/src/main/java/com/iemr/flw/service/health/HealthService.java new file mode 100644 index 000000000..084ffe5e4 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/health/HealthService.java @@ -0,0 +1,517 @@ +/* +* 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.service.health; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.time.Instant; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; +import jakarta.annotation.PreDestroy; +import javax.sql.DataSource; +import com.zaxxer.hikari.HikariDataSource; +import com.zaxxer.hikari.HikariPoolMXBean; +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +@Service +public class HealthService { + + private static final Logger logger = LoggerFactory.getLogger(HealthService.class); + + private static final String STATUS_KEY = "status"; + private static final String STATUS_UP = "UP"; + private static final String STATUS_DOWN = "DOWN"; + private static final String STATUS_DEGRADED = "DEGRADED"; + private static final String SEVERITY_KEY = "severity"; + private static final String SEVERITY_OK = "OK"; + private static final String SEVERITY_WARNING = "WARNING"; + private static final String SEVERITY_CRITICAL = "CRITICAL"; + private static final String ERROR_KEY = "error"; + private static final String MESSAGE_KEY = "message"; + private static final String RESPONSE_TIME_KEY = "responseTimeMs"; + private static final long MYSQL_TIMEOUT_SECONDS = 3; + private static final long REDIS_TIMEOUT_SECONDS = 3; + + private static final long ADVANCED_CHECKS_THROTTLE_SECONDS = 30; + private static final long RESPONSE_TIME_THRESHOLD_MS = 2000; + + private static final String DIAGNOSTIC_LOCK_WAIT = "MYSQL_LOCK_WAIT"; + private static final String DIAGNOSTIC_SLOW_QUERIES = "MYSQL_SLOW_QUERIES"; + private static final String DIAGNOSTIC_POOL_EXHAUSTED = "MYSQL_POOL_EXHAUSTED"; + private static final String DIAGNOSTIC_LOG_TEMPLATE = "Diagnostic: {}"; + + private final DataSource dataSource; + private final RedisTemplate redisTemplate; + private final ExecutorService executorService; + + private volatile long lastAdvancedCheckTime = 0; + private volatile AdvancedCheckResult cachedAdvancedCheckResult = null; + private final ReentrantReadWriteLock advancedCheckLock = new ReentrantReadWriteLock(); + private final AtomicBoolean advancedCheckInProgress = new AtomicBoolean(false); + + private static final boolean ADVANCED_HEALTH_CHECKS_ENABLED = true; + + public HealthService(DataSource dataSource, + @Autowired(required = false) RedisTemplate redisTemplate) { + this.dataSource = dataSource; + this.redisTemplate = redisTemplate; + this.executorService = Executors.newFixedThreadPool(6); + } + + @PreDestroy + public void shutdown() { + if (executorService != null && !executorService.isShutdown()) { + try { + executorService.shutdown(); + if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) { + executorService.shutdownNow(); + logger.warn("ExecutorService did not terminate gracefully"); + } + } catch (InterruptedException e) { + executorService.shutdownNow(); + Thread.currentThread().interrupt(); + logger.warn("ExecutorService shutdown interrupted", e); + } + } + } + + public Map checkHealth() { + Map response = new LinkedHashMap<>(); + response.put("timestamp", Instant.now().toString()); + + Map mysqlStatus = new ConcurrentHashMap<>(); + Map redisStatus = new ConcurrentHashMap<>(); + + if (!executorService.isShutdown()) { + performHealthChecks(mysqlStatus, redisStatus); + } + + ensurePopulated(mysqlStatus, "MySQL"); + ensurePopulated(redisStatus, "Redis"); + + Map> components = new LinkedHashMap<>(); + components.put("mysql", mysqlStatus); + components.put("redis", redisStatus); + + response.put("components", components); + response.put(STATUS_KEY, computeOverallStatus(components)); + + return response; + } + + private void performHealthChecks(Map mysqlStatus, Map redisStatus) { + Future mysqlFuture = null; + Future redisFuture = null; + try { + mysqlFuture = executorService.submit( + () -> performHealthCheck("MySQL", mysqlStatus, this::checkMySQLHealthSync)); + redisFuture = executorService.submit( + () -> performHealthCheck("Redis", redisStatus, this::checkRedisHealthSync)); + + awaitHealthChecks(mysqlFuture, redisFuture); + } catch (TimeoutException e) { + logger.warn("Health check aggregate timeout after {} seconds", getMaxTimeout()); + cancelFutures(mysqlFuture, redisFuture); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.warn("Health check was interrupted"); + cancelFutures(mysqlFuture, redisFuture); + } catch (Exception e) { + logger.warn("Health check execution error: {}", e.getMessage()); + cancelFutures(mysqlFuture, redisFuture); + } + } + + private void awaitHealthChecks(Future mysqlFuture, Future redisFuture) throws TimeoutException, InterruptedException, ExecutionException { + long maxTimeout = getMaxTimeout(); + long deadlineNs = System.nanoTime() + TimeUnit.SECONDS.toNanos(maxTimeout); + + mysqlFuture.get(maxTimeout, TimeUnit.SECONDS); + long remainingNs = deadlineNs - System.nanoTime(); + + if (remainingNs > 0) { + redisFuture.get(remainingNs, TimeUnit.NANOSECONDS); + } else { + redisFuture.cancel(true); + } + } + + private long getMaxTimeout() { + return Math.max(MYSQL_TIMEOUT_SECONDS, REDIS_TIMEOUT_SECONDS) + 1; + } + + private void cancelFutures(Future mysqlFuture, Future redisFuture) { + if (mysqlFuture != null) mysqlFuture.cancel(true); + if (redisFuture != null) redisFuture.cancel(true); + } + + private void ensurePopulated(Map status, String componentName) { + if (!status.containsKey(STATUS_KEY)) { + status.put(STATUS_KEY, STATUS_DOWN); + status.put(SEVERITY_KEY, SEVERITY_CRITICAL); + status.put(ERROR_KEY, componentName + " health check did not complete in time"); + } + } + + private HealthCheckResult checkMySQLHealthSync() { + try (Connection connection = dataSource.getConnection(); + PreparedStatement stmt = connection.prepareStatement("SELECT 1 as health_check")) { + + stmt.setQueryTimeout((int) MYSQL_TIMEOUT_SECONDS); + + try (ResultSet rs = stmt.executeQuery()) { + if (!rs.next()) { + return new HealthCheckResult(false, "No result from health check query", false); + } + } + } catch (Exception e) { + logger.warn("MySQL health check failed: {}", e.getMessage(), e); + return new HealthCheckResult(false, "MySQL connection failed", false); + } + boolean isDegraded = performAdvancedMySQLChecksWithThrottle(); + return new HealthCheckResult(true, null, isDegraded); + } + + private HealthCheckResult checkRedisHealthSync() { + if (redisTemplate == null) { + return new HealthCheckResult(true, "Redis not configured — skipped", false); + } + + try { + String pong = redisTemplate.execute((org.springframework.data.redis.core.RedisCallback) (connection) -> connection.ping()); + + if ("PONG".equals(pong)) { + return new HealthCheckResult(true, null, false); + } + + return new HealthCheckResult(false, "Redis PING failed", false); + + } catch (Exception e) { + logger.warn("Redis health check failed: {}", e.getMessage(), e); + return new HealthCheckResult(false, "Redis connection failed", false); + } + } + + private Map performHealthCheck(String componentName, + Map status, + Supplier checker) { + long startTime = System.currentTimeMillis(); + + try { + HealthCheckResult result = checker.get(); + long responseTime = System.currentTimeMillis() - startTime; + + String componentStatus; + if (!result.isHealthy) { + componentStatus = STATUS_DOWN; + } else if (result.isDegraded) { + componentStatus = STATUS_DEGRADED; + } else { + componentStatus = STATUS_UP; + } + status.put(STATUS_KEY, componentStatus); + + status.put(RESPONSE_TIME_KEY, responseTime); + + String severity = determineSeverity(result.isHealthy, responseTime, result.isDegraded); + status.put(SEVERITY_KEY, severity); + + if (result.error != null) { + String fieldKey = result.isHealthy ? MESSAGE_KEY : ERROR_KEY; + status.put(fieldKey, result.error); + } + + return status; + + } catch (Exception e) { + long responseTime = System.currentTimeMillis() - startTime; + logger.error("{} health check failed with exception: {}", componentName, e.getMessage(), e); + + status.put(STATUS_KEY, STATUS_DOWN); + status.put(RESPONSE_TIME_KEY, responseTime); + status.put(SEVERITY_KEY, SEVERITY_CRITICAL); + status.put(ERROR_KEY, "Health check failed with an unexpected error"); + + return status; + } + } + + private String determineSeverity(boolean isHealthy, long responseTimeMs, boolean isDegraded) { + if (!isHealthy) { + return SEVERITY_CRITICAL; + } + + if (isDegraded) { + return SEVERITY_WARNING; + } + + if (responseTimeMs > RESPONSE_TIME_THRESHOLD_MS) { + return SEVERITY_WARNING; + } + + return SEVERITY_OK; + } + + private String computeOverallStatus(Map> components) { + boolean hasCritical = false; + boolean hasDegraded = false; + + for (Map componentStatus : components.values()) { + String status = (String) componentStatus.get(STATUS_KEY); + String severity = (String) componentStatus.get(SEVERITY_KEY); + + if (STATUS_DOWN.equals(status) || SEVERITY_CRITICAL.equals(severity)) { + hasCritical = true; + } + + if (STATUS_DEGRADED.equals(status)) { + hasDegraded = true; + } + + if (SEVERITY_WARNING.equals(severity)) { + hasDegraded = true; + } + } + + if (hasCritical) { + return STATUS_DOWN; + } + + if (hasDegraded) { + return STATUS_DEGRADED; + } + + return STATUS_UP; + } + + private boolean performAdvancedMySQLChecksWithThrottle() { + if (!ADVANCED_HEALTH_CHECKS_ENABLED) { + return false; + } + + long currentTime = System.currentTimeMillis(); + + advancedCheckLock.readLock().lock(); + try { + if (cachedAdvancedCheckResult != null && + (currentTime - lastAdvancedCheckTime) < ADVANCED_CHECKS_THROTTLE_SECONDS * 1000) { + return cachedAdvancedCheckResult.isDegraded; + } + } finally { + advancedCheckLock.readLock().unlock(); + } + + // Only one thread may submit; others fall back to the (stale) cache + if (!advancedCheckInProgress.compareAndSet(false, true)) { + advancedCheckLock.readLock().lock(); + try { + return cachedAdvancedCheckResult != null && cachedAdvancedCheckResult.isDegraded; + } finally { + advancedCheckLock.readLock().unlock(); + } + } + + try { + // Perform DB I/O outside the write lock to avoid lock contention + AdvancedCheckResult result; + try (Connection connection = dataSource.getConnection()) { + result = performAdvancedMySQLChecks(connection); + } catch (Exception e) { + if (e.getCause() instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + logger.debug("Failed to get connection for advanced checks: {}", e.getMessage()); + result = new AdvancedCheckResult(false); + } + + // Re-acquire write lock only to update the cache atomically + advancedCheckLock.writeLock().lock(); + try { + lastAdvancedCheckTime = currentTime; + cachedAdvancedCheckResult = result; + return result.isDegraded; + } finally { + advancedCheckLock.writeLock().unlock(); + } + } finally { + advancedCheckInProgress.set(false); + } + } + + private AdvancedCheckResult performAdvancedMySQLChecks(Connection connection) { + try { + boolean hasIssues = false; + + if (hasLockWaits(connection)) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_LOCK_WAIT); + hasIssues = true; + } + + if (hasSlowQueries(connection)) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_SLOW_QUERIES); + hasIssues = true; + } + + if (hasConnectionPoolExhaustion()) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_POOL_EXHAUSTED); + hasIssues = true; + } + + return new AdvancedCheckResult(hasIssues); + } catch (Exception e) { + logger.debug("Advanced MySQL checks encountered exception, marking degraded"); + return new AdvancedCheckResult(true); + } + } + + private boolean hasLockWaits(Connection connection) { + try (PreparedStatement stmt = connection.prepareStatement( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST " + + "WHERE (state = 'Waiting for table metadata lock' " + + " OR state = 'Waiting for row lock' " + + " OR state = 'Waiting for lock') " + + "AND user = SUBSTRING_INDEX(USER(), '@', 1)")) { + stmt.setQueryTimeout(2); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + int lockCount = rs.getInt(1); + return lockCount > 0; + } + } + } catch (Exception e) { + logger.debug("Could not check for lock waits"); + } + return false; + } + + + private boolean hasSlowQueries(Connection connection) { + try (PreparedStatement stmt = connection.prepareStatement( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST " + + "WHERE command != 'Sleep' AND time > ? AND user = SUBSTRING_INDEX(USER(), '@', 1)")) { + stmt.setQueryTimeout(2); + stmt.setInt(1, 10); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + int slowQueryCount = rs.getInt(1); + return slowQueryCount > 3; + } + } + } catch (Exception e) { + logger.debug("Could not check for slow queries"); + } + return false; + } + + private boolean hasConnectionPoolExhaustion() { + if (dataSource instanceof HikariDataSource hikariDataSource) { + try { + HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean(); + + if (poolMXBean != null) { + int activeConnections = poolMXBean.getActiveConnections(); + int maxPoolSize = hikariDataSource.getMaximumPoolSize(); + + int threshold = (int) (maxPoolSize * 0.8); + return activeConnections > threshold; + } + } catch (Exception e) { + logger.debug("Could not retrieve HikariCP pool metrics"); + } + } + + return checkPoolMetricsViaJMX(); + } + + private boolean checkPoolMetricsViaJMX() { + try { + MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + ObjectName objectName = new ObjectName("com.zaxxer.hikari:type=Pool (*)"); + var mBeans = mBeanServer.queryMBeans(objectName, null); + + for (var mBean : mBeans) { + if (evaluatePoolMetrics(mBeanServer, mBean.getObjectName())) { + return true; + } + } + } catch (Exception e) { + logger.debug("Could not access HikariCP pool metrics via JMX"); + } + + logger.debug("Pool exhaustion check disabled: HikariCP metrics unavailable"); + return false; + } + + private boolean evaluatePoolMetrics(MBeanServer mBeanServer, ObjectName objectName) { + try { + Integer activeConnections = (Integer) mBeanServer.getAttribute(objectName, "ActiveConnections"); + Integer maximumPoolSize = (Integer) mBeanServer.getAttribute(objectName, "MaximumPoolSize"); + + if (activeConnections != null && maximumPoolSize != null) { + int threshold = (int) (maximumPoolSize * 0.8); + return activeConnections > threshold; + } + } catch (Exception e) { + // Continue to next MBean + } + return false; + } + + private static class AdvancedCheckResult { + final boolean isDegraded; + + AdvancedCheckResult(boolean isDegraded) { + this.isDegraded = isDegraded; + } + } + + private static class HealthCheckResult { + final boolean isHealthy; + final String error; + final boolean isDegraded; + + HealthCheckResult(boolean isHealthy, String error, boolean isDegraded) { + this.isHealthy = isHealthy; + this.error = error; + this.isDegraded = isDegraded; + } + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java new file mode 100644 index 000000000..15ca0e7cc --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java @@ -0,0 +1,198 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.controller.AbhaBeneficiaryController; +import com.iemr.flw.domain.iemr.AbhaApiResponse; +import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; +import com.iemr.flw.dto.iemr.AbhaRequestDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.identity.HouseHoldRepo; +import com.iemr.flw.service.AbhaBeneficiaryService; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class AbhaBeneficiaryServiceImpl implements AbhaBeneficiaryService { + + private final org.slf4j.Logger logger = LoggerFactory.getLogger(AbhaBeneficiaryService.class); + + + @Autowired + private BeneficiaryRepo beneficiaryRepo; + + + + @Value("${govthealth.user.details.url}") + private String getUserDetailsUrl; + + @Value("${govthealth.user.id}") + private String govthealthUserId; + + @Value("${govthealth.password}") + private String govthealthPassword; + + @Autowired + private HouseHoldRepo houseHoldRepo; + + @Override + public Object getBeneficiaryByAbha(AbhaRequestDTO request) { + + try { + Long benRedId = null; + BigInteger benDetailsdId = null; + String familyId =null; + if(request.getHouseHoldId()!=null){ + benRedId = beneficiaryRepo.findByHouseoldId(request.getHouseHoldId()).get(0).getBenRegId(); + if(benRedId!=null){ + benDetailsdId = beneficiaryRepo.findByBenRegIdFromMapping(BigInteger.valueOf(benRedId)).getBenDetailsId(); + + } + if(benDetailsdId!=null){ + familyId = beneficiaryRepo.findByBeneficiaryDetailsId(benDetailsdId).getFamilyId(); + + } + } + + Object[] benHealthIdNumber = beneficiaryRepo.getHealthIdNumber(request.getCardNo()); + if (benHealthIdNumber != null && benHealthIdNumber.length > 0) { + Object[] healthData = (Object[]) benHealthIdNumber[0]; + String healthIdNumber = healthData[0] != null ? healthData[0].toString() : null; + String healthId = healthData[1] != null ? healthData[1].toString() : null; + logger.info("healthIdNumber:"+healthIdNumber); + logger.info("healthId:"+healthId); + if (request.getCardNo().equals(healthIdNumber)) { + + Map response = new HashMap<>(); + response.put("statusCode", 5000); + response.put("message", + "This ABHA No already exists"); + + return response; + } + } + + AbhaApiResponse abhaApiResponse = + getAbhaResponse(request.getCardNo()).getBody(); + + if (abhaApiResponse == null || abhaApiResponse.getData() == null) { + + Map response = new HashMap<>(); + response.put("statusCode", 5001); + response.put("message", "No data found"); + + return response; + } + + + for (AbhaBeneficiaryDTO dto : abhaApiResponse.getData()) { + + // Check if ABHA already exists in system + benHealthIdNumber = beneficiaryRepo.getHealthIdNumber(dto.getAbhaId()); + if (benHealthIdNumber != null && benHealthIdNumber.length > 0) { + Object[] healthData = (Object[]) benHealthIdNumber[0]; + String healthIdNumber = healthData[0] != null ? healthData[0].toString() : null; + String healthId = healthData[1] != null ? healthData[1].toString() : null; + logger.info("healthIdNumber:"+healthIdNumber); + logger.info("healthId:"+healthId); + if (dto.getAbhaId().equals(healthIdNumber)) { + + Map response = new HashMap<>(); + response.put("statusCode", 5000); + response.put("message", + "Beneficiary is already exists"); + + return response; + } + } + if(familyId!=null){ + if(!dto.getFamilyid().toString().equals(familyId)){ + Map response = new HashMap<>(); + response.put("statusCode", 5000); + response.put("message", + "Beneficiary is not associated with this family."); + + return response; + } + } + + + + + // Split name into firstName and lastName + String personName = dto.getPersonName(); + + if (personName != null + && !personName.trim().isEmpty()) { + + String[] names = + personName.trim().split("\\s+", 2); + + dto.setFirstName(names[0]); + + if (names.length > 1) { + dto.setLastName(names[1]); + } else { + dto.setLastName(""); + } + } + } + + + logger.info("ABHA Response Status : {}", + abhaApiResponse.getStatusCode()); + + logger.info("ABHA Response : {}", + new Gson().toJson(abhaApiResponse)); + + return abhaApiResponse; + + } catch (Exception e) { + + logger.error("Error while fetching beneficiary by ABHA", e); + + Map response = new HashMap<>(); + response.put("statusCode", 5000); + response.put("message", "Internal Server Error"); + + return response; + } + } + + public ResponseEntity getAbhaResponse(String requestId) { + RestTemplate restTemplate = new RestTemplate(); + + Map body = new HashMap<>(); + body.put("userId",govthealthUserId); + body.put("password", govthealthPassword); + body.put("cardNo", requestId); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity request = new HttpEntity<>(body, headers); + + ResponseEntity response = restTemplate.exchange( + getUserDetailsUrl, + HttpMethod.POST, + request, + AbhaApiResponse.class + ); + + System.out.println("Status = " + response.getStatusCode()); + System.out.println("Body = " + response.getBody()); + + return response; + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/AbhaTokenServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AbhaTokenServiceImpl.java new file mode 100644 index 000000000..eef104e8c --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/AbhaTokenServiceImpl.java @@ -0,0 +1,103 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.iemr.flw.service.AbhaTokenService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +@Service +public class AbhaTokenServiceImpl implements AbhaTokenService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + private static Map ABHA_TOKEN_RESPONSE; + private static Long ABHA_TOKEN_EXP; + + @Value("${abha.client.id}") + private String clientId; + + @Value("${abha.client.secret}") + private String clientSecret; + + @Value("${abha.token.url}") + private String abhaTokenUrl; + + @Value("${abha.xcmid:sbx}") + private String xCmId; + + @Override + public synchronized Map getAbhaToken() throws Exception { + try { + if (ABHA_TOKEN_RESPONSE == null || ABHA_TOKEN_EXP == null + || ABHA_TOKEN_EXP < System.currentTimeMillis()) { + generateAbhaToken(); + logger.info("ABHA token generated successfully"); + } + } catch (Exception e) { + logger.error("Error generating ABHA token: " + e.getMessage()); + throw new Exception("Failed to generate ABHA token: " + e.getMessage()); + } + return ABHA_TOKEN_RESPONSE; + } + + private void generateAbhaToken() throws Exception { + RestTemplate restTemplate = new RestTemplate(); + + Map requestBody = new HashMap<>(); + requestBody.put("clientId", clientId); + requestBody.put("clientSecret", clientSecret); + requestBody.put("grantType", "client_credentials"); + + String requestJson = new Gson().toJson(requestBody); + + MultiValueMap headers = new LinkedMultiValueMap<>(); + headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8"); + headers.add("REQUEST-ID", UUID.randomUUID().toString()); + + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + df.setTimeZone(tz); + headers.add("TIMESTAMP", df.format(new Date())); + headers.add("X-CM-ID", xCmId); + + HttpEntity httpEntity = new HttpEntity<>(requestJson, headers); + ResponseEntity responseEntity = restTemplate.exchange( + abhaTokenUrl, HttpMethod.POST, httpEntity, String.class); + + String responseBody = responseEntity.getBody(); + if (responseBody != null) { + JsonObject jsonResponse = JsonParser.parseString(responseBody).getAsJsonObject(); + + Map tokenResponse = new HashMap<>(); + tokenResponse.put("accessToken", jsonResponse.get("accessToken").getAsString()); + tokenResponse.put("expiresIn", jsonResponse.get("expiresIn").getAsInt()); + tokenResponse.put("refreshExpiresIn", jsonResponse.get("refreshExpiresIn").getAsInt()); + tokenResponse.put("refreshToken", jsonResponse.get("refreshToken").getAsString()); + tokenResponse.put("tokenType", jsonResponse.get("tokenType").getAsString()); + + Integer expiresIn = jsonResponse.get("expiresIn").getAsInt(); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, expiresIn); + ABHA_TOKEN_EXP = calendar.getTimeInMillis(); + + ABHA_TOKEN_RESPONSE = tokenResponse; + } else { + throw new Exception("Empty response from ABDM token API"); + } + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java index 43986a8c9..8be992afe 100644 --- a/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java @@ -126,7 +126,7 @@ private void checkAndAddIncentives(AdolescentHealth adolescentHealth) { if (sellingSanitaryActivity != null) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(sellingSanitaryActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(sellingSanitaryActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue(),adolescentHealth.getUserId()); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(sellingSanitaryActivity.getId()); @@ -151,7 +151,7 @@ record = new IncentiveActivityRecord(); if (mobilizingADHActivity != null) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(mobilizingADHActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(mobilizingADHActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue(),adolescentHealth.getUserId()); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(mobilizingADHActivity.getId()); diff --git a/src/main/java/com/iemr/flw/service/impl/AshaProfileImpl.java b/src/main/java/com/iemr/flw/service/impl/AshaProfileImpl.java index 29ca30da1..fe7b04dbb 100644 --- a/src/main/java/com/iemr/flw/service/impl/AshaProfileImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/AshaProfileImpl.java @@ -1,19 +1,17 @@ package com.iemr.flw.service.impl; import com.iemr.flw.domain.iemr.AshaWorker; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; +import com.iemr.flw.dto.iemr.UserServiceRoleDTO; import com.iemr.flw.repo.iemr.AshaProfileRepo; import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.AshaProfileService; import com.iemr.flw.service.EmployeeMasterInter; import com.iemr.flw.repo.iemr.EmployeeMasterRepo; -import com.iemr.flw.service.AshaProfileService; -import com.iemr.flw.service.EmployeeMasterInter; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtAuthenticationUtil; import com.iemr.flw.utils.JwtUtil; -import com.iemr.flw.utils.exception.IEMRException; -import io.jsonwebtoken.Claims; import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,12 +20,9 @@ import java.time.LocalDate; import java.util.Objects; +import java.util.Optional; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.util.Objects; -import java.util.concurrent.TimeUnit; @Service public class AshaProfileImpl implements AshaProfileService { @@ -45,6 +40,9 @@ public class AshaProfileImpl implements AshaProfileService { JwtAuthenticationUtil jwtAuthenticationUtil; @Autowired private UserServiceRoleRepo userServiceRoleRepo; + + @Autowired + private UserService userService; private final Logger logger = LoggerFactory.getLogger(AshaProfileImpl.class); @Transactional @@ -53,16 +51,17 @@ public AshaWorker saveEditData(AshaWorker request) { try { Objects.requireNonNull(request, "ASHA worker request must not be null"); - Long id = request.getId(); + Optional ashaWorker = ashaProfileRepo.findByEmployeeId(request.getEmployeeId()); // ---------- CREATE Case ---------- - if (id == null || id == 0) { - // treat id=0 as null (frontend mistake) - if (id != null && id == 0) { - request.setId(null); - } + if (!ashaWorker.isPresent()) { + request.setId(null); - AshaWorker saved = ashaProfileRepo.save(request); + UserServiceRoleDTO userServiceRoleDTO= userService.getUserDetail(request.getEmployeeId()); + if(userServiceRoleDTO!=null){ + request.setName(userServiceRoleDTO.getName()); + } + AshaWorker saved = saveProfile(request); logger.info("Created ASHA Worker: {}", saved.getId()); return saved; } @@ -96,22 +95,15 @@ public AshaWorker getProfileData(Integer userId) { private AshaWorker getDetails(Integer userID) { try { - M_User m_user = Objects.requireNonNull(employeeMasterInter.getUserDetails(userID), "User details not found for ID: " + userID); + User m_user = Objects.requireNonNull(employeeMasterInter.getUserDetails(userID), "User details not found for ID: " + userID); AshaWorker ashaWorker = new AshaWorker(); ashaWorker.setEmployeeId(m_user.getUserID()); - // Convert DOB (Timestamp) to LocalDate - java.sql.Timestamp dobTimestamp = m_user.getDOB(); - LocalDate dob = dobTimestamp != null ? dobTimestamp.toLocalDateTime().toLocalDate() : null; - ashaWorker.setDob(dob); - // Convert DOJ (Timestamp) to LocalDate - java.sql.Timestamp dojTimestamp = m_user.getDOJ(); - LocalDate doj = dojTimestamp != null ? dojTimestamp.toLocalDateTime().toLocalDate() : LocalDate.now(); - ashaWorker.setDateOfJoining(doj); + ashaWorker.setName(String.format("%s %s", Objects.toString(m_user.getFirstName(), ""), Objects.toString(m_user.getLastName(), "")).trim()); ashaWorker.setMobileNumber(m_user.getContactNo()); ashaWorker.setAlternateMobileNumber(m_user.getEmergencyContactNo()); ashaWorker.setProviderServiceMapID(m_user.getServiceProviderID()); - ashaWorker.setProfileImage(""); + ashaWorker.setProfileImage(null); ashaWorker.setSupervisorName(""); ashaWorker.setAwwName(""); ashaWorker.setVillage(""); @@ -140,8 +132,104 @@ private AshaWorker getDetails(Integer userID) { throw new RuntimeException("Failed to create ASHA worker profile from user details", e); } } + @Transactional + public AshaWorker saveProfile(AshaWorker request) { + logger.info("Saving ASHA Profile for EmployeeId: {}", request.getEmployeeId()); + + logger.info("Received DOB: {}", request.getDob()); + logger.info("Received Date Of Joining: {}", request.getDateOfJoining()); + + AshaWorker existing = ashaProfileRepo + .findByEmployeeId(request.getEmployeeId()) + .orElse(new AshaWorker()); + + if (isValid(request.getName())) + existing.setName(request.getName()); + + if (isValid(request.getVillage())) + existing.setVillage(request.getVillage()); + + if (request.getEmployeeId() != null) + existing.setEmployeeId(request.getEmployeeId()); + + // Save even if null + existing.setDob(request.getDob()); + + if (isValid(request.getMobileNumber())) + existing.setMobileNumber(request.getMobileNumber()); + + if (isValid(request.getAlternateMobileNumber())) + existing.setAlternateMobileNumber(request.getAlternateMobileNumber()); + + if (isValid(request.getFatherOrSpouseName())) + existing.setFatherOrSpouseName(request.getFatherOrSpouseName()); + + // Save even if null + existing.setDateOfJoining(request.getDateOfJoining()); + + if (isValid(request.getBankAccount())) + existing.setBankAccount(request.getBankAccount()); + + if (isValid(request.getIfsc())) + existing.setIfsc(request.getIfsc()); + + if (request.getPopulationCovered() != null) + existing.setPopulationCovered(request.getPopulationCovered()); + + if (isValid(request.getChoName())) + existing.setChoName(request.getChoName()); + + if (isValid(request.getChoMobile())) + existing.setChoMobile(request.getChoMobile()); + + if (isValid(request.getAwwName())) + existing.setAwwName(request.getAwwName()); + + if (isValid(request.getAwwMobile())) + existing.setAwwMobile(request.getAwwMobile()); + + if (isValid(request.getAnm1Name())) + existing.setAnm1Name(request.getAnm1Name()); + + if (isValid(request.getAnm1Mobile())) + existing.setAnm1Mobile(request.getAnm1Mobile()); + + if (isValid(request.getAnm2Name())) + existing.setAnm2Name(request.getAnm2Name()); + + if (isValid(request.getAnm2Mobile())) + existing.setAnm2Mobile(request.getAnm2Mobile()); + + if (isValid(request.getAbhaNumber())) + existing.setAbhaNumber(request.getAbhaNumber()); + + if (isValid(request.getAshaHouseholdRegistration())) + existing.setAshaHouseholdRegistration(request.getAshaHouseholdRegistration()); + + if (isValid(request.getAshaFamilyMember())) + existing.setAshaFamilyMember(request.getAshaFamilyMember()); + + if (request.getProviderServiceMapID() != null) + existing.setProviderServiceMapID(request.getProviderServiceMapID()); + + if (request.getProfileImage() != null && request.getProfileImage().length > 0) + existing.setProfileImage(request.getProfileImage()); + + if (request.getIsFatherOrSpouse() != null) + existing.setIsFatherOrSpouse(request.getIsFatherOrSpouse()); + + if (isValid(request.getSupervisorName())) + existing.setSupervisorName(request.getSupervisorName()); + + if (isValid(request.getSupervisorMobile())) + existing.setSupervisorMobile(request.getSupervisorMobile()); + + return ashaProfileRepo.save(existing); + } + - public AshaWorker updateProfile(AshaWorker request) { + + public AshaWorker updateProfile(AshaWorker request) { AshaWorker existing = ashaProfileRepo.findByEmployeeId(request.getEmployeeId()).orElseThrow(() -> new RuntimeException("ASHA worker not found")); if (isValid(request.getAbhaNumber())) existing.setAbhaNumber(request.getAbhaNumber()); if (request.getEmployeeId() != null) existing.setEmployeeId(request.getEmployeeId()); @@ -169,16 +257,20 @@ public AshaWorker updateProfile(AshaWorker request) { if (isValid(request.getAwwMobile())) existing.setAwwMobile(request.getAwwMobile()); if (request.getProviderServiceMapID() != null) existing.setProviderServiceMapID(request.getProviderServiceMapID()); - if (isValid(request.getProfileImage())) existing.setProfileImage(request.getProfileImage()); + if (isValidImage(request.getProfileImage())) existing.setProfileImage(request.getProfileImage()); if (request.getIsFatherOrSpouse() != null) existing.setIsFatherOrSpouse(request.getIsFatherOrSpouse()); if (isValid(request.getSupervisorName())) existing.setSupervisorName(request.getSupervisorName()); if (isValid(request.getSupervisorMobile())) existing.setSupervisorMobile(request.getSupervisorMobile()); - return existing; + return ashaProfileRepo.save(existing); } private boolean isValid(String value) { return value != null && !value.trim().isEmpty() && !"null".equalsIgnoreCase(value.trim()); } + private boolean isValidImage(byte[] value) { + return value != null && value.length > 0; + } + } 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 510d4b536..23c4bd602 100644 --- a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java @@ -2,16 +2,19 @@ import java.math.BigInteger; import java.sql.Date; +import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.Period; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.iemr.flw.domain.iemr.EyeCheckupVisit; import com.iemr.flw.domain.iemr.IncentiveActivity; @@ -19,6 +22,8 @@ import com.iemr.flw.dto.iemr.EyeCheckupRequestDTO; import com.iemr.flw.masterEnum.GroupName; import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,6 +59,7 @@ import com.iemr.flw.service.BeneficiaryService; import com.iemr.flw.utils.config.ConfigProperties; import com.iemr.flw.utils.http.HttpUtils; +import org.springframework.transaction.annotation.Transactional; @Service @Qualifier("rmnchServiceImpl") @@ -90,56 +96,69 @@ public class BeneficiaryServiceImpl implements BeneficiaryService { private JwtUtil jwtUtil; @Autowired - private UserServiceRoleRepo userRepo; + private UserService userService; - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + @Autowired + private IncentiveLogicService incentiveLogicService; + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); @Override public String getBenData(GetBenRequestHandler request, String authorisation) throws Exception { - String outputResponse = null; - int totalPage = 0; - try { - if (request != null && request.getAshaId() != null) { - List resultSet; - Integer pageSize = Integer.valueOf(door_to_door_page_size); - if (request.getPageNo() != null) { - String userName = beneficiaryRepo.getUserName(request.getAshaId()); - if (userName == null || userName.isEmpty()) - throw new Exception("Asha details not found, please contact administrator"); - - request.setUserName(userName); - - PageRequest pr = PageRequest.of(request.getPageNo(), pageSize); - if (request.getFromDate() != null && request.getToDate() != null) { - Page p = beneficiaryRepo.getBenDataWithinDates( - request.getUserName(), request.getFromDate(), request.getToDate(), pr); - resultSet = p.getContent(); - totalPage = p.getTotalPages(); - } else { - Page p = beneficiaryRepo.getBenDataByUser(request.getUserName(), - pr); - resultSet = p.getContent(); - totalPage = p.getTotalPages(); - } - if (resultSet != null && resultSet.size() > 0) { - outputResponse = getMappingsForAddressIDs(resultSet, totalPage, authorisation); - } - } else { - // page no not invalid - throw new Exception("Invalid page no"); - } - } else - throw new Exception("Invalid/missing village details"); - } catch (Exception e) { - throw new Exception(e.getMessage()); + if (request == null || request.getAshaId() == null) { + throw new Exception("Invalid/missing asha details"); + } + + if (request.getPageNo() == null || request.getPageNo() < 0) { + throw new Exception("Invalid page number"); + } + + String userName = beneficiaryRepo.getUserName(request.getAshaId()); + + if (userName == null || userName.isEmpty()) { + throw new Exception("Asha details not found, please contact administrator"); } - return outputResponse; + request.setUserName(userName); + + int pageSize = Integer.parseInt(door_to_door_page_size); + PageRequest pageRequest = PageRequest.of(request.getPageNo(), pageSize); + + Page pageResult; + + // ✅ Date Filter Handling + if (request.getFromDate() != null && request.getToDate() != null) { + + if (request.getFromDate().after(request.getToDate())) { + throw new Exception("Invalid date range"); + } + + pageResult = beneficiaryRepo.getBenDataWithinDates( + userName, + request.getFromDate(), + request.getToDate(), + pageRequest + ); + + } else { + + pageResult = beneficiaryRepo.getBenDataByUser(userName, pageRequest); + } + + if (!pageResult.hasContent()) { + return null; + } + + return getMappingsForAddressIDs( + pageResult.getContent(), + pageResult.getTotalPages(), + authorisation + ); } + private String getMappingsForAddressIDs(List addressList, int totalPage, String authorisation) { RMNCHHouseHoldDetails benHouseHoldRMNCH_ROBJ; @@ -158,276 +177,291 @@ private String getMappingsForAddressIDs(List addressLi for (RMNCHMBeneficiaryaddress a : addressList) { // exception by-passing try { - RMNCHMBeneficiarymapping m = beneficiaryRepo.getByAddressID(a.getId()); - if (m != null) { - benHouseHoldRMNCH_ROBJ = new RMNCHHouseHoldDetails(); - benDetailsRMNCH_OBJ = new RMNCHBeneficiaryDetailsRmnch(); - benBotnBirthRMNCH_ROBJ = new RMNCHBornBirthDetails(); - - benDetailsOBJ = new RMNCHMBeneficiarydetail(); - benAccountOBJ = new RMNCHMBeneficiaryAccount(); - benImageOBJ = new RMNCHMBeneficiaryImage(); - benAddressOBJ = new RMNCHMBeneficiaryaddress(); - benContactOBJ = new RMNCHMBeneficiarycontact(); - Map healthDetails = getBenHealthDetails(m.getBenRegId()); - if (m.getBenDetailsId() != null) { - benDetailsOBJ = beneficiaryRepo.getDetailsById(m.getBenDetailsId()); - } - if (m.getBenAccountID() != null) { - benAccountOBJ = beneficiaryRepo.getAccountById(m.getBenAccountID()); - } - if (m.getBenImageId() != null) { - benImageOBJ = beneficiaryRepo.getImageById(m.getBenImageId().longValue()); - } - if (m.getBenAddressId() != null) { - benAddressOBJ = beneficiaryRepo.getAddressById(m.getBenAddressId()); - } - if (m.getBenContactsId() != null) { - benContactOBJ = beneficiaryRepo.getContactById(m.getBenContactsId()); - } + if(!beneficiaryRepo.getByAddressID(a.getId()).isEmpty()){ + RMNCHMBeneficiarymapping m = beneficiaryRepo.getByAddressID(a.getId()).get(0); + if (m != null) { + benHouseHoldRMNCH_ROBJ = new RMNCHHouseHoldDetails(); + benDetailsRMNCH_OBJ = new RMNCHBeneficiaryDetailsRmnch(); + benBotnBirthRMNCH_ROBJ = new RMNCHBornBirthDetails(); + + benDetailsOBJ = new RMNCHMBeneficiarydetail(); + benAccountOBJ = new RMNCHMBeneficiaryAccount(); + benImageOBJ = new RMNCHMBeneficiaryImage(); + benAddressOBJ = new RMNCHMBeneficiaryaddress(); + benContactOBJ = new RMNCHMBeneficiarycontact(); + Map healthDetails = getBenHealthDetails(m.getBenRegId()); + if (m.getBenDetailsId() != null) { + benDetailsOBJ = beneficiaryRepo.getDetailsById(m.getBenDetailsId()); + } + if (m.getBenAccountID() != null) { + benAccountOBJ = beneficiaryRepo.getAccountById(m.getBenAccountID()); + } + if (m.getBenImageId() != null) { + benImageOBJ = beneficiaryRepo.getImageById(m.getBenImageId().longValue()); + } + if (m.getBenAddressId() != null) { + benAddressOBJ = beneficiaryRepo.getAddressById(m.getBenAddressId()); + } + if (m.getBenContactsId() != null) { + benContactOBJ = beneficiaryRepo.getContactById(m.getBenContactsId()); + } - BigInteger benID = null; - if (m.getBenRegId() != null) - benID = beneficiaryRepo.getBenIdFromRegID(m.getBenRegId().longValue()); + BigInteger benID = null; + if (m.getBenRegId() != null) + benID = beneficiaryRepo.getBenIdFromRegID(m.getBenRegId().longValue()); - if (m.getBenRegId() != null) { - benDetailsRMNCH_OBJ = beneficiaryRepo - .getDetailsByRegID((m.getBenRegId()).longValue()); - benBotnBirthRMNCH_ROBJ = beneficiaryRepo.getBornBirthByRegID((m.getBenRegId()).longValue()); + if (m.getBenRegId() != null) { + if(!beneficiaryRepo + .getDetailsByRegID((m.getBenRegId()).longValue()).isEmpty()){ + benDetailsRMNCH_OBJ = beneficiaryRepo + .getDetailsByRegID((m.getBenRegId()).longValue()).get(0); - if (benDetailsRMNCH_OBJ != null && benDetailsRMNCH_OBJ.getHouseoldId() != null) - benHouseHoldRMNCH_ROBJ = houseHoldRepo - .getByHouseHoldID(benDetailsRMNCH_OBJ.getHouseoldId()); + } + benBotnBirthRMNCH_ROBJ = beneficiaryRepo.getBornBirthByRegID((m.getBenRegId()).longValue()); - } - if (benDetailsRMNCH_OBJ == null) - benDetailsRMNCH_OBJ = new RMNCHBeneficiaryDetailsRmnch(); - // new mapping 30-06-2021 - if (benDetailsOBJ.getMotherName() != null) - benDetailsRMNCH_OBJ.setMotherName(benDetailsOBJ.getMotherName()); - if (benDetailsOBJ.getLiteracyStatus() != null) - benDetailsRMNCH_OBJ.setLiteracyStatus(benDetailsOBJ.getLiteracyStatus()); - - // bank - if (benAccountOBJ.getNameOfBank() != null) - benDetailsRMNCH_OBJ.setNameOfBank(benAccountOBJ.getNameOfBank()); - if (benAccountOBJ.getBranchName() != null) - benDetailsRMNCH_OBJ.setBranchName(benAccountOBJ.getBranchName()); - if (benAccountOBJ.getIfscCode() != null) - benDetailsRMNCH_OBJ.setIfscCode(benAccountOBJ.getIfscCode()); - if (benAccountOBJ.getBankAccount() != null) - benDetailsRMNCH_OBJ.setBankAccount(benAccountOBJ.getBankAccount()); - - // location - if (benAddressOBJ.getCountyid() != null) - benDetailsRMNCH_OBJ.setCountryId(benAddressOBJ.getCountyid()); - if (benAddressOBJ.getPermCountry() != null) - benDetailsRMNCH_OBJ.setCountryName(benAddressOBJ.getPermCountry()); - - if (benAddressOBJ.getStatePerm() != null) - benDetailsRMNCH_OBJ.setStateId(benAddressOBJ.getStatePerm()); - if (benAddressOBJ.getPermState() != null) - benDetailsRMNCH_OBJ.setStateName(benAddressOBJ.getPermState()); - - if (benAddressOBJ.getDistrictidPerm() != null) { - benDetailsRMNCH_OBJ.setDistrictid(benAddressOBJ.getDistrictidPerm()); + if (benDetailsRMNCH_OBJ != null && benDetailsRMNCH_OBJ.getHouseoldId() != null) + if(!houseHoldRepo + .getByHouseHoldID(benDetailsRMNCH_OBJ.getHouseoldId()).isEmpty()){ + benHouseHoldRMNCH_ROBJ = houseHoldRepo + .getByHouseHoldID(benDetailsRMNCH_OBJ.getHouseoldId()).get(0); + } - } - if (benAddressOBJ.getDistrictnamePerm() != null) { - benDetailsRMNCH_OBJ.setDistrictname(benAddressOBJ.getDistrictnamePerm()); - } + } + if (benDetailsRMNCH_OBJ == null) + benDetailsRMNCH_OBJ = new RMNCHBeneficiaryDetailsRmnch(); + + // new mapping 30-06-2021 + if (benDetailsOBJ.getMotherName() != null) + benDetailsRMNCH_OBJ.setMotherName(benDetailsOBJ.getMotherName()); + if (benDetailsOBJ.getLiteracyStatus() != null) + benDetailsRMNCH_OBJ.setLiteracyStatus(benDetailsOBJ.getLiteracyStatus()); + + // bank + if (benAccountOBJ.getNameOfBank() != null) + benDetailsRMNCH_OBJ.setNameOfBank(benAccountOBJ.getNameOfBank()); + if (benAccountOBJ.getBranchName() != null) + benDetailsRMNCH_OBJ.setBranchName(benAccountOBJ.getBranchName()); + if (benAccountOBJ.getIfscCode() != null) + benDetailsRMNCH_OBJ.setIfscCode(benAccountOBJ.getIfscCode()); + if (benAccountOBJ.getBankAccount() != null) + benDetailsRMNCH_OBJ.setBankAccount(benAccountOBJ.getBankAccount()); + + // location + if (benAddressOBJ.getCountyid() != null) + benDetailsRMNCH_OBJ.setCountryId(benAddressOBJ.getCountyid()); + if (benAddressOBJ.getPermCountry() != null) + benDetailsRMNCH_OBJ.setCountryName(benAddressOBJ.getPermCountry()); + + if (benAddressOBJ.getStatePerm() != null) + benDetailsRMNCH_OBJ.setStateId(benAddressOBJ.getStatePerm()); + if (benAddressOBJ.getPermState() != null) + benDetailsRMNCH_OBJ.setStateName(benAddressOBJ.getPermState()); + + if (benAddressOBJ.getDistrictidPerm() != null) { + benDetailsRMNCH_OBJ.setDistrictid(benAddressOBJ.getDistrictidPerm()); - if (benAddressOBJ.getPermSubDistrictId() != null) - benDetailsRMNCH_OBJ.setBlockId(benAddressOBJ.getPermSubDistrictId()); - if (benAddressOBJ.getPermSubDistrict() != null) - benDetailsRMNCH_OBJ.setBlockName(benAddressOBJ.getPermSubDistrict()); - - if (benAddressOBJ.getVillageidPerm() != null) - benDetailsRMNCH_OBJ.setVillageId(benAddressOBJ.getVillageidPerm()); - if (benAddressOBJ.getVillagenamePerm() != null) - benDetailsRMNCH_OBJ.setVillageName(benAddressOBJ.getVillagenamePerm()); - - if (benAddressOBJ.getPermServicePointId() != null) - benDetailsRMNCH_OBJ.setServicePointID(benAddressOBJ.getPermServicePointId()); - if (benAddressOBJ.getPermServicePoint() != null) - benDetailsRMNCH_OBJ.setServicePointName(benAddressOBJ.getPermServicePoint()); - - if (benAddressOBJ.getPermZoneID() != null) - benDetailsRMNCH_OBJ.setZoneID(benAddressOBJ.getPermZoneID()); - if (benAddressOBJ.getPermZone() != null) - benDetailsRMNCH_OBJ.setZoneName(benAddressOBJ.getPermZone()); - - if (benAddressOBJ.getPermAddrLine1() != null) - benDetailsRMNCH_OBJ.setAddressLine1(benAddressOBJ.getPermAddrLine1()); - if (benAddressOBJ.getPermAddrLine2() != null) - benDetailsRMNCH_OBJ.setAddressLine2(benAddressOBJ.getPermAddrLine2()); - if (benAddressOBJ.getPermAddrLine3() != null) - benDetailsRMNCH_OBJ.setAddressLine3(benAddressOBJ.getPermAddrLine3()); - - // ----------------------------------------------------------------------------- - - // related benids - if (benDetailsRMNCH_OBJ.getRelatedBeneficiaryIdsDB() != null) { - - String[] relatedBenIDsString = benDetailsRMNCH_OBJ.getRelatedBeneficiaryIdsDB().split(","); - Long[] relatedBenIDs = new Long[relatedBenIDsString.length]; - int pointer = 0; - for (String s : relatedBenIDsString) { - relatedBenIDs[pointer] = Long.valueOf(s); - pointer++; } + if (benAddressOBJ.getDistrictnamePerm() != null) { + benDetailsRMNCH_OBJ.setDistrictname(benAddressOBJ.getDistrictnamePerm()); - benDetailsRMNCH_OBJ.setRelatedBeneficiaryIds(relatedBenIDs); - } - // ------------------------------------------------------------------------------ - - if (benDetailsOBJ.getCommunity() != null) - benDetailsRMNCH_OBJ.setCommunity(benDetailsOBJ.getCommunity()); - if (benDetailsOBJ.getCommunityId() != null) - benDetailsRMNCH_OBJ.setCommunityId(benDetailsOBJ.getCommunityId()); - if (benContactOBJ.getPreferredPhoneNum() != null) - benDetailsRMNCH_OBJ.setContact_number(benContactOBJ.getPreferredPhoneNum()); - - if (benDetailsOBJ.getDob() != null) - benDetailsRMNCH_OBJ.setDob(benDetailsOBJ.getDob()); - if (benDetailsOBJ.getFatherName() != null) - benDetailsRMNCH_OBJ.setFatherName(benDetailsOBJ.getFatherName()); - if (benDetailsOBJ.getFirstName() != null) - benDetailsRMNCH_OBJ.setFirstName(benDetailsOBJ.getFirstName()); - if (benDetailsOBJ.getGender() != null) - benDetailsRMNCH_OBJ.setGender(benDetailsOBJ.getGender()); - if (benDetailsOBJ.getGenderId() != null) - benDetailsRMNCH_OBJ.setGenderId(benDetailsOBJ.getGenderId()); - - if (benDetailsOBJ.getMaritalstatus() != null) - benDetailsRMNCH_OBJ.setMaritalstatus(benDetailsOBJ.getMaritalstatus()); - if (benDetailsOBJ.getMaritalstatusId() != null) - benDetailsRMNCH_OBJ.setMaritalstatusId(benDetailsOBJ.getMaritalstatusId()); - if (benDetailsOBJ.getMarriageDate() != null) - benDetailsRMNCH_OBJ.setMarriageDate(benDetailsOBJ.getMarriageDate()); - - if (benDetailsOBJ.getReligion() != null) - benDetailsRMNCH_OBJ.setReligion(benDetailsOBJ.getReligion()); - if (benDetailsOBJ.getReligionID() != null) - benDetailsRMNCH_OBJ.setReligionID(benDetailsOBJ.getReligionID()); - if (benDetailsOBJ.getSpousename() != null) - benDetailsRMNCH_OBJ.setSpousename(benDetailsOBJ.getSpousename()); - - if (benImageOBJ != null && benImageOBJ.getUser_image() != null) - benDetailsRMNCH_OBJ.setUser_image(benImageOBJ.getUser_image()); - - // new fields + } + + if (benAddressOBJ.getPermSubDistrictId() != null) + benDetailsRMNCH_OBJ.setBlockId(benAddressOBJ.getPermSubDistrictId()); + if (benAddressOBJ.getPermSubDistrict() != null) + benDetailsRMNCH_OBJ.setBlockName(benAddressOBJ.getPermSubDistrict()); + + if (benAddressOBJ.getVillageidPerm() != null) + benDetailsRMNCH_OBJ.setVillageId(benAddressOBJ.getVillageidPerm()); + if (benAddressOBJ.getVillagenamePerm() != null) + benDetailsRMNCH_OBJ.setVillageName(benAddressOBJ.getVillagenamePerm()); + + if (benAddressOBJ.getPermServicePointId() != null) + benDetailsRMNCH_OBJ.setServicePointID(benAddressOBJ.getPermServicePointId()); + if (benAddressOBJ.getPermServicePoint() != null) + benDetailsRMNCH_OBJ.setServicePointName(benAddressOBJ.getPermServicePoint()); + + if (benAddressOBJ.getPermZoneID() != null) + benDetailsRMNCH_OBJ.setZoneID(benAddressOBJ.getPermZoneID()); + if (benAddressOBJ.getPermZone() != null) + benDetailsRMNCH_OBJ.setZoneName(benAddressOBJ.getPermZone()); + + if (benAddressOBJ.getPermAddrLine1() != null) + benDetailsRMNCH_OBJ.setAddressLine1(benAddressOBJ.getPermAddrLine1()); + if (benAddressOBJ.getPermAddrLine2() != null) + benDetailsRMNCH_OBJ.setAddressLine2(benAddressOBJ.getPermAddrLine2()); + if (benAddressOBJ.getPermAddrLine3() != null) + benDetailsRMNCH_OBJ.setAddressLine3(benAddressOBJ.getPermAddrLine3()); + + // ----------------------------------------------------------------------------- + + // related benids + if (benDetailsRMNCH_OBJ.getRelatedBeneficiaryIdsDB() != null) { + + String[] relatedBenIDsString = benDetailsRMNCH_OBJ.getRelatedBeneficiaryIdsDB().split(","); + Long[] relatedBenIDs = new Long[relatedBenIDsString.length]; + int pointer = 0; + for (String s : relatedBenIDsString) { + relatedBenIDs[pointer] = Long.valueOf(s); + pointer++; + } + + benDetailsRMNCH_OBJ.setRelatedBeneficiaryIds(relatedBenIDs); + } + // ------------------------------------------------------------------------------ + + if (benDetailsOBJ.getCommunity() != null) + benDetailsRMNCH_OBJ.setCommunity(benDetailsOBJ.getCommunity()); + if (benDetailsOBJ.getCommunityId() != null) + benDetailsRMNCH_OBJ.setCommunityId(benDetailsOBJ.getCommunityId()); + if (benContactOBJ.getPreferredPhoneNum() != null) + benDetailsRMNCH_OBJ.setContact_number(benContactOBJ.getPreferredPhoneNum()); + + if (benDetailsOBJ.getDob() != null) + benDetailsRMNCH_OBJ.setDob(benDetailsOBJ.getDob()); + if (benDetailsOBJ.getFatherName() != null) + benDetailsRMNCH_OBJ.setFatherName(benDetailsOBJ.getFatherName()); + if (benDetailsOBJ.getFirstName() != null) + benDetailsRMNCH_OBJ.setFirstName(benDetailsOBJ.getFirstName()); + if (benDetailsOBJ.getGender() != null) + benDetailsRMNCH_OBJ.setGender(benDetailsOBJ.getGender()); + if (benDetailsOBJ.getGenderId() != null) + benDetailsRMNCH_OBJ.setGenderId(benDetailsOBJ.getGenderId()); + + if (benDetailsOBJ.getMaritalstatus() != null) + benDetailsRMNCH_OBJ.setMaritalstatus(benDetailsOBJ.getMaritalstatus()); + if (benDetailsOBJ.getMaritalstatusId() != null) + benDetailsRMNCH_OBJ.setMaritalstatusId(benDetailsOBJ.getMaritalstatusId()); + if (benDetailsOBJ.getMarriageDate() != null) + benDetailsRMNCH_OBJ.setMarriageDate(benDetailsOBJ.getMarriageDate()); + + if (benDetailsOBJ.getReligion() != null) + benDetailsRMNCH_OBJ.setReligion(benDetailsOBJ.getReligion()); + if (benDetailsOBJ.getReligionID() != null) + benDetailsRMNCH_OBJ.setReligionID(benDetailsOBJ.getReligionID()); + if (benDetailsOBJ.getSpousename() != null) + benDetailsRMNCH_OBJ.setSpousename(benDetailsOBJ.getSpousename()); + + if (benImageOBJ != null && benImageOBJ.getUser_image() != null) + benDetailsRMNCH_OBJ.setUser_image(benImageOBJ.getUser_image()); + + // new fields // benDetailsRMNCH_OBJ.setRegistrationDate(benDetailsOBJ.getCreatedDate()); - if (benID != null) - benDetailsRMNCH_OBJ.setBenficieryid(benID.longValue()); - - if (benDetailsOBJ.getLastName() != null) - benDetailsRMNCH_OBJ.setLastName(benDetailsOBJ.getLastName()); - - if (benDetailsRMNCH_OBJ.getCreatedBy() == null) - if (benDetailsOBJ.getCreatedBy() != null) - benDetailsRMNCH_OBJ.setCreatedBy(benDetailsOBJ.getCreatedBy()); - - // age calculation - String ageDetails = ""; - int age_val = 0; - String ageUnit = null; - if (benDetailsOBJ.getDob() != null) { - - Date date = new Date(benDetailsOBJ.getDob().getTime()); - Calendar cal = Calendar.getInstance(); - - cal.setTime(date); - - int year = cal.get(Calendar.YEAR); - int month = cal.get(Calendar.MONTH) + 1; - int day = cal.get(Calendar.DAY_OF_MONTH); - - java.time.LocalDate todayDate = java.time.LocalDate.now(); - java.time.LocalDate birthdate = java.time.LocalDate.of(year, month, day); - Period p = Period.between(birthdate, todayDate); - - int d = p.getDays(); - int mo = p.getMonths(); - int y = p.getYears(); - - if (y > 0) { - ageDetails = y + " years - " + mo + " months"; - age_val = y; - ageUnit = (age_val > 1) ? "Years" : "Year"; - } else { - if (mo > 0) { - ageDetails = mo + " months - " + d + " days"; - age_val = mo; - ageUnit = (age_val > 1) ? "Months" : "Month"; + if (benID != null) + benDetailsRMNCH_OBJ.setBenficieryid(benID.longValue()); + + if (benDetailsOBJ.getLastName() != null) + benDetailsRMNCH_OBJ.setLastName(benDetailsOBJ.getLastName()); + + if (benDetailsRMNCH_OBJ.getCreatedBy() == null) + if (benDetailsOBJ.getCreatedBy() != null) + benDetailsRMNCH_OBJ.setCreatedBy(benDetailsOBJ.getCreatedBy()); + + // age calculation + String ageDetails = ""; + int age_val = 0; + String ageUnit = null; + if (benDetailsOBJ.getDob() != null) { + + Date date = new Date(benDetailsOBJ.getDob().getTime()); + Calendar cal = Calendar.getInstance(); + + cal.setTime(date); + + int year = cal.get(Calendar.YEAR); + int month = cal.get(Calendar.MONTH) + 1; + int day = cal.get(Calendar.DAY_OF_MONTH); + + java.time.LocalDate todayDate = java.time.LocalDate.now(); + java.time.LocalDate birthdate = java.time.LocalDate.of(year, month, day); + Period p = Period.between(birthdate, todayDate); + + int d = p.getDays(); + int mo = p.getMonths(); + int y = p.getYears(); + + if (y > 0) { + ageDetails = y + " years - " + mo + " months"; + age_val = y; + ageUnit = (age_val > 1) ? "Years" : "Year"; } else { - ageDetails = d + " days"; - age_val = d; - ageUnit = (age_val > 1) ? "Days" : "Day"; + if (mo > 0) { + ageDetails = mo + " months - " + d + " days"; + age_val = mo; + ageUnit = (age_val > 1) ? "Months" : "Month"; + } else { + ageDetails = d + " days"; + age_val = d; + ageUnit = (age_val > 1) ? "Days" : "Day"; + } } - } - } + } - benDetailsRMNCH_OBJ.setAgeFull(ageDetails); - benDetailsRMNCH_OBJ.setAge(age_val); - if (ageUnit != null) - benDetailsRMNCH_OBJ.setAge_unit(ageUnit); - - resultMap = new HashMap<>(); - if (benHouseHoldRMNCH_ROBJ != null) - resultMap.put("householdDetails", benHouseHoldRMNCH_ROBJ); - else - resultMap.put("householdDetails", new HashMap()); - - if (benBotnBirthRMNCH_ROBJ != null) - resultMap.put("bornbirthDeatils", benBotnBirthRMNCH_ROBJ); - else - resultMap.put("bornbirthDeatils", new HashMap()); - - resultMap.put("beneficiaryDetails", benDetailsRMNCH_OBJ); - resultMap.put("abhaHealthDetails", healthDetails); - resultMap.put("houseoldId", benDetailsRMNCH_OBJ.getHouseoldId()); - resultMap.put("benficieryid", benDetailsRMNCH_OBJ.getBenficieryid()); - resultMap.put("isDeath", benDetailsRMNCH_OBJ.getIsDeath()); - resultMap.put("isDeathValue", benDetailsRMNCH_OBJ.getIsDeathValue()); - resultMap.put("dateOfDeath",benDetailsRMNCH_OBJ.getDateOfDeath()); - resultMap.put("timeOfDeath", benDetailsRMNCH_OBJ.getTimeOfDeath()); - resultMap.put("reasonOfDeath", benDetailsRMNCH_OBJ.getReasonOfDeath()); - resultMap.put("reasonOfDeathId", benDetailsRMNCH_OBJ.getReasonOfDeathId()); - resultMap.put("placeOfDeath", benDetailsRMNCH_OBJ.getPlaceOfDeath()); - resultMap.put("placeOfDeathId", benDetailsRMNCH_OBJ.getPlaceOfDeathId()); - resultMap.put("isSpouseAdded", benDetailsRMNCH_OBJ.getIsSpouseAdded()); - resultMap.put("isChildrenAdded", benDetailsRMNCH_OBJ.getIsChildrenAdded()); - resultMap.put("noOfchildren", benDetailsRMNCH_OBJ.getNoOfchildren()); - resultMap.put("isMarried", benDetailsRMNCH_OBJ.getIsMarried()); - resultMap.put("doYouHavechildren", benDetailsRMNCH_OBJ.getDoYouHavechildren()); - resultMap.put("noofAlivechildren ",benDetailsRMNCH_OBJ.getNoofAlivechildren()); - - - - resultMap.put("BenRegId", m.getBenRegId()); - - // adding asha id / created by - user id - if (benAddressOBJ.getCreatedBy() != null) { - Integer userID = beneficiaryRepo.getUserIDByUserName(benAddressOBJ.getCreatedBy()); - if (userID != null && userID > 0) - resultMap.put("ashaId", userID); - } - // get HealthID of ben - if (m.getBenRegId() != null) { - fetchHealthIdByBenRegID(m.getBenRegId().longValue(), authorisation, resultMap); - } + benDetailsRMNCH_OBJ.setAgeFull(ageDetails); + benDetailsRMNCH_OBJ.setAge(age_val); + if (ageUnit != null) + benDetailsRMNCH_OBJ.setAge_unit(ageUnit); + + resultMap = new HashMap<>(); + if (benHouseHoldRMNCH_ROBJ != null) + resultMap.put("householdDetails", benHouseHoldRMNCH_ROBJ); + else + resultMap.put("householdDetails", new HashMap()); + + if (benBotnBirthRMNCH_ROBJ != null) + resultMap.put("bornbirthDeatils", benBotnBirthRMNCH_ROBJ); + else + resultMap.put("bornbirthDeatils", new HashMap()); + + resultMap.put("beneficiaryDetails", benDetailsRMNCH_OBJ); + resultMap.put("abhaHealthDetails", healthDetails); + resultMap.put("houseoldId", benDetailsRMNCH_OBJ.getHouseoldId()); + resultMap.put("benficieryid", benDetailsRMNCH_OBJ.getBenficieryid()); + resultMap.put("isDeath", benDetailsRMNCH_OBJ.getIsDeath()); + resultMap.put("isDeathValue", benDetailsRMNCH_OBJ.getIsDeathValue()); + resultMap.put("dateOfDeath",benDetailsRMNCH_OBJ.getDateOfDeath()); + resultMap.put("timeOfDeath", benDetailsRMNCH_OBJ.getTimeOfDeath()); + resultMap.put("reasonOfDeath", benDetailsRMNCH_OBJ.getReasonOfDeath()); + resultMap.put("reasonOfDeathId", benDetailsRMNCH_OBJ.getReasonOfDeathId()); + resultMap.put("placeOfDeath", benDetailsRMNCH_OBJ.getPlaceOfDeath()); + resultMap.put("placeOfDeathId", benDetailsRMNCH_OBJ.getPlaceOfDeathId()); + resultMap.put("isSpouseAdded", benDetailsRMNCH_OBJ.getIsSpouseAdded()); + resultMap.put("isChildrenAdded", benDetailsRMNCH_OBJ.getIsChildrenAdded()); + resultMap.put("noOfchildren", benDetailsRMNCH_OBJ.getNoOfchildren()); + resultMap.put("isMarried", benDetailsRMNCH_OBJ.getIsMarried()); + resultMap.put("doYouHavechildren", benDetailsRMNCH_OBJ.getDoYouHavechildren()); + resultMap.put("noofAlivechildren",benDetailsRMNCH_OBJ.getNoofAlivechildren()); + resultMap.put("isDeactivate", benDetailsRMNCH_OBJ.getIsDeactivate() != null + ? benDetailsRMNCH_OBJ.getIsDeactivate() + : false + ); + resultMap.put("BenRegId", m.getBenRegId()); + + // adding asha id / created by - user id + if (benAddressOBJ.getCreatedBy() != null) { + Integer userID = beneficiaryRepo.getUserIDByUserName(benAddressOBJ.getCreatedBy()); + if (userID != null && userID > 0) + resultMap.put("ashaId", userID); + } + // get HealthID of ben + if (m.getBenRegId() != null) { + fetchHealthIdByBenRegID(m.getBenRegId().longValue(), authorisation, resultMap); + } - resultList.add(resultMap); + resultList.add(resultMap); - } else { - // mapping not available + } else { + // mapping not available + } } + } catch (Exception e) { - logger.error("error for addressID :"+e.getMessage() + a.getId() + " and vanID : " + a.getVanID()); + logger.info("Error for ben :"+e.getMessage()); + logger.info("Error for ben :"+e); + logger.error("error for addressID :" + e.getMessage() + a.getId() + " and vanID : " + a.getVanID()); } } @@ -440,33 +474,33 @@ private String getMappingsForAddressIDs(List addressLi } - private Map getBenHealthDetails(BigInteger benRegId) { - Map healthDetails = new HashMap<>(); - if (null != benRegId) { - Object[] benHealthIdNumber = beneficiaryRepo.getBenHealthIdNumber(benRegId); - if (benHealthIdNumber != null && benHealthIdNumber.length > 0) { - Object[] healthData = (Object[]) benHealthIdNumber[0]; - String healthIdNumber = healthData[0] != null ? healthData[0].toString() : null; - String healthId = healthData[1] != null ? healthData[1].toString() : null; - - if (null != healthIdNumber) { - List health = beneficiaryRepo.getBenHealthDetails(healthIdNumber); - if (health != null && !health.isEmpty()) { - for (Object[] objects : health) { - healthDetails.put("HealthID", objects[0]); - healthDetails.put("HealthIdNumber", objects[1]); - healthDetails.put("isNewAbha", objects[2]); - } - } else { - healthDetails.put("HealthIdNumber", healthIdNumber); - healthDetails.put("HealthID", healthId); - healthDetails.put("isNewAbha", null); - } - } - } - } - return healthDetails; - } + private Map getBenHealthDetails(BigInteger benRegId) { + Map healthDetails = new HashMap<>(); + if (null != benRegId) { + Object[] benHealthIdNumber = beneficiaryRepo.getBenHealthIdNumber(benRegId); + if (benHealthIdNumber != null && benHealthIdNumber.length > 0) { + Object[] healthData = (Object[]) benHealthIdNumber[0]; + String healthIdNumber = healthData[0] != null ? healthData[0].toString() : null; + String healthId = healthData[1] != null ? healthData[1].toString() : null; + + if (null != healthIdNumber) { + List health = beneficiaryRepo.getBenHealthDetails(healthIdNumber); + if (health != null && !health.isEmpty()) { + for (Object[] objects : health) { + healthDetails.put("HealthID", objects[0]); + healthDetails.put("HealthIdNumber", objects[1]); + healthDetails.put("isNewAbha", objects[2]); + } + } else { + healthDetails.put("HealthIdNumber", healthIdNumber); + healthDetails.put("HealthID", healthId); + healthDetails.put("isNewAbha", null); + } + } + } + } + return healthDetails; + } private Map getBenBenVisitDetails(BigInteger benRegId) { Map healthDetails = new HashMap<>(); @@ -484,7 +518,7 @@ private Map getBenBenVisitDetails(BigInteger benRegId) { return healthDetails; } - public void fetchHealthIdByBenRegID(Long benRegID, String authorization, Map resultMap) { + public void fetchHealthIdByBenRegID(Long benRegID, String authorization, Map resultMap) { Map requestMap = new HashMap(); requestMap.put("beneficiaryRegID", benRegID); requestMap.put("beneficiaryID", null); @@ -523,7 +557,7 @@ public void fetchHealthIdByBenRegID(Long benRegID, String authorization, Map eyeCheckupRequestDTOS) { + public String saveEyeCheckupVsit(List eyeCheckupRequestDTOS, String token) { try { for (EyeCheckupRequestDTO dto : eyeCheckupRequestDTOS) { @@ -531,41 +565,72 @@ public String saveEyeCheckupVsit(List eyeCheckupRequestDTO visit.setBeneficiaryId(dto.getBeneficiaryId()); visit.setHouseholdId(dto.getHouseHoldId()); - visit.setUserId(userRepo.getUserIdByName(jwtUtil.getUserNameFromStorage())); // cache se lena hai + visit.setUserId(jwtUtil.extractUserId(token)); visit.setCreatedBy(dto.getUserName()); - StringBuilder sb = new StringBuilder(); - - // fields mapping EyeCheckupListDTO f = dto.getFields(); - sb.append(f.getDischarge_summary_upload()); - String longText = sb.toString(); + + visit.setSymptomsObserved(f.getSymptomsAsString()); + + String upload = f.getDischarge_summary_upload(); + visit.setDischargeSummaryUpload( + (upload != null && !upload.equalsIgnoreCase("null")) ? upload : null + ); + visit.setVisitDate(LocalDate.parse(f.getVisit_date(), FORMATTER)); - visit.setSymptomsObserved(f.getSymptoms_observed()); + + visit.setDateOfSurgery(f.getDate_of_surgery()); + + visit.setEyeAffected(f.getEye_affected()); visit.setReferredTo(f.getReferred_to()); - visit.setDischargeSummaryUpload(longText); visit.setFollowUpStatus(f.getFollow_up_status()); - visit.setDateOfSurgery(f.getDate_of_surgery()); - // save/update eyeCheckUpVisitRepo.save(visit); + if (visit.getReferredTo() != null) { + if (visit.getReferredTo().equals("Govt Public Facility")) { + LocalDate localDate = visit.getVisitDate(); + + Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); + incentiveLogicService.incentiveForEyeSurgeyReferGovtHospital(visit.getBeneficiaryId(), visitDate, visitDate, visit.getUserId()); + } + + if (visit.getReferredTo().equals("Private Facility")) { + LocalDate localDate = visit.getVisitDate(); + + Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); + incentiveLogicService.incentiveForEyeSurgeyReferPrivateHospital(visit.getBeneficiaryId(), visitDate, visitDate, visit.getUserId()); + } + } + } + return "Eye checkup data saved successfully."; - } catch (Exception e) { + + } catch (DateTimeParseException e) { e.printStackTrace(); + throw new RuntimeException("Invalid date format. Expected dd-MM-yyyy. " + e.getMessage()); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Failed to save eye checkup data: " + e.getMessage()); } - return null ; } @Override - public List getEyeCheckUpVisit(GetBenRequestHandler request) { - List visits = eyeCheckUpVisitRepo.findByUserId(request.getAshaId()); + public List getEyeCheckUpVisit(GetBenRequestHandler request,String token) { + String createdBy = null; + try { + createdBy = userService.getUserDetail(jwtUtil.extractUserId(token)).getUserName(); + } catch (Exception e) { + logger.error("Error extracting userId from token: " + e.getMessage()); + } + List visits = eyeCheckUpVisitRepo.findByCreatedBy(createdBy); return visits.stream().map(v -> { EyeCheckupRequestDTO dto = new EyeCheckupRequestDTO(); dto.setId(v.getId()); + dto.setEyeSide(v.getEyeAffected()); dto.setBeneficiaryId(v.getBeneficiaryId()); dto.setHouseHoldId(v.getHouseholdId()); dto.setUserName(v.getCreatedBy()); @@ -582,6 +647,22 @@ public List getEyeCheckUpVisit(GetBenRequestHandler reques dto.setFields(fields); + if (v.getReferredTo() != null) { + if (v.getReferredTo().equals("Govt Public Facility")) { + LocalDate localDate = v.getVisitDate(); + + Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); + incentiveLogicService.incentiveForEyeSurgeyReferGovtHospital(v.getBeneficiaryId(), visitDate, visitDate, v.getUserId()); + } + + if (v.getReferredTo().equals("Private Facility")) { + LocalDate localDate = v.getVisitDate(); + + Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); + incentiveLogicService.incentiveForEyeSurgeyReferPrivateHospital(v.getBeneficiaryId(), visitDate, visitDate, v.getUserId()); + } + } + return dto; }).collect(Collectors.toList()); } diff --git a/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java new file mode 100644 index 000000000..f9c076327 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java @@ -0,0 +1,507 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.CampaignService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collections; +import java.util.List; + +@Service +public class CampaignServiceImpl implements CampaignService { + + @Autowired + private OrsCampaignRepo orsCampaignRepo; + + @Autowired + private PulsePolioCampaignRepo pulsePolioCampaignRepo; + + @Autowired + private FilariasisCampaignRepo filariasisCampaignRepo; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + IncentivesRepo incentivesRepo; + + @Autowired + IncentiveRecordRepo recordRepo; + + @Autowired + private ObjectMapper objectMapper = new ObjectMapper(); + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; + + @Override + @Transactional + public List saveOrsCampaign(List orsCampaignDTO, String token) throws IEMRException, JsonProcessingException { + if (orsCampaignDTO == null || orsCampaignDTO.isEmpty()) { + return Collections.emptyList(); // + } + + List campaignOrsRequest = new ArrayList<>(); + Integer userId = jwtUtil.extractUserId(token); + String userName = userServiceRoleRepo.getUserNamedByUserId(userId); + + for (OrsCampaignDTO campaignDTO : orsCampaignDTO) { + if (campaignDTO.getFields() == null) { + continue; + } + + CampaignOrs campaignOrsEntity = new CampaignOrs(); + campaignOrsEntity.setUserId(userId); + campaignOrsEntity.setCreatedBy(userName); + campaignOrsEntity.setUpdatedBy(userName); + campaignOrsEntity.setStartDate(campaignDTO.getFields().getStartDate()); + campaignOrsEntity.setEndDate(campaignDTO.getFields().getEndDate()); + + try { + String familiesStr = campaignDTO.getFields().getNumberOfFamilies(); + if (familiesStr != null && !familiesStr.trim().isEmpty()) { + double familiesDouble = Double.parseDouble(familiesStr); + campaignOrsEntity.setNumberOfFamilies((int) familiesDouble); + } else { + campaignOrsEntity.setNumberOfFamilies(0); // default 0 + } + } catch (NumberFormatException e) { + throw new IEMRException("Invalid number format for families: " + campaignDTO.getFields().getNumberOfFamilies()); + } + + OrsCampaignListDTO campaignListDTO = campaignDTO.getFields(); + + if(campaignListDTO!=null){ + String photosJson = objectMapper.writeValueAsString(campaignListDTO.getCampaignPhotos()); + campaignOrsEntity.setCampaignPhotos(photosJson); + } + + campaignOrsRequest.add(campaignOrsEntity); + } + + if (!campaignOrsRequest.isEmpty()) { + List savedCampaigns = orsCampaignRepo.saveAll(campaignOrsRequest); + savedCampaigns.forEach(ors->{ + checkMonthlyPulseOrsDistribution(ors.getUserId(),ors.getStartDate(),ors.getEndDate()); + }); + return savedCampaigns; + } + + return Collections.emptyList(); + } + + @Override + public List getOrsCampaign(String token) throws IEMRException { + Integer userId = jwtUtil.extractUserId(token); + List orsCampaignDTOSResponse = new ArrayList<>(); + int page = 0; + int pageSize = 10; + Page campaignOrsPage; + do { + Pageable pageable = PageRequest.of(page, pageSize); + campaignOrsPage = orsCampaignRepo.findByUserId(userId, pageable); + for (CampaignOrs campaignOrs : campaignOrsPage.getContent()) { + OrsCampaignResponseDTO dto = convertOrsToDTO(campaignOrs); + orsCampaignDTOSResponse.add(dto); + } + page++; + } while (campaignOrsPage.hasNext()); + return orsCampaignDTOSResponse; + } + + + @Override + @Transactional + public List savePolioCampaign(List polioCampaignDTOs, String token) + throws IEMRException, JsonProcessingException { + + if (polioCampaignDTOs == null || polioCampaignDTOs.isEmpty()) { + throw new IEMRException("Campaign data is required"); + } + + List campaignPolioRequest = new ArrayList<>(); + Integer userId = jwtUtil.extractUserId(token); + String userName = userServiceRoleRepo.getUserNamedByUserId(userId); + + for (PolioCampaignDTO campaignDTO : polioCampaignDTOs) { + if (campaignDTO.getFields() == null) { + continue; + } + + PulsePolioCampaign campaignPolioEntity = new PulsePolioCampaign(); + campaignPolioEntity.setUserId(userId); + campaignPolioEntity.setCreatedBy(userName); + campaignPolioEntity.setUpdatedBy(userName); + + // Set start and end dates + campaignPolioEntity.setStartDate(campaignDTO.getFields().getStartDate()); + campaignPolioEntity.setEndDate(campaignDTO.getFields().getEndDate()); + + // Parse number of children + try { + String childrenStr = campaignDTO.getFields().getNumberOfChildren(); + if (childrenStr != null && !childrenStr.trim().isEmpty()) { + try { + // parse as double first, then cast to int + double childrenDouble = Double.parseDouble(childrenStr); + campaignPolioEntity.setNumberOfChildren((int) childrenDouble); + } catch (NumberFormatException e) { + campaignPolioEntity.setNumberOfChildren(0); // default 0 if invalid + } + } else { + campaignPolioEntity.setNumberOfChildren(0); + } + } catch (NumberFormatException e) { + throw new IEMRException("Invalid number format for children: " + e.getMessage()); + } + + // Convert photos to base64 JSON array + + PolioCampaignListDTO polioCampaignListDTO = campaignDTO.getFields(); + if(polioCampaignListDTO!=null){ + String photosJson = objectMapper.writeValueAsString(polioCampaignListDTO.getCampaignPhotos()); + campaignPolioEntity.setCampaignPhotos(photosJson); + + + } + + campaignPolioRequest.add(campaignPolioEntity); + } + + if (!campaignPolioRequest.isEmpty()) { + List savedCampaigns = pulsePolioCampaignRepo.saveAll(campaignPolioRequest); + savedCampaigns.forEach(this::checkIncentiveForPulsePolio); + + return savedCampaigns; + } + + throw new IEMRException("No valid campaign data to save"); + } + + private void checkIncentiveForPulsePolio(PulsePolioCampaign pulsePolioCampaign){ + checkMonthlyPulsePolioIncentive(pulsePolioCampaign.getUserId(),pulsePolioCampaign.getStartDate(),pulsePolioCampaign.getEndDate()); + + } + + @Override + @Transactional + public List saveFilariasisCampaign(List filariasisCampaignDTOS, String token) throws IEMRException, JsonProcessingException { + + if (filariasisCampaignDTOS == null || filariasisCampaignDTOS.isEmpty()) { + throw new IEMRException("Campaign data is required"); + } + + List campaignPolioRequest = new ArrayList<>(); + Integer userId = jwtUtil.extractUserId(token); + String userName = userServiceRoleRepo.getUserNamedByUserId(userId); + + for (FilariasisCampaignDTO campaignDTO : filariasisCampaignDTOS) { + if (campaignDTO.getFields() == null) { + continue; + } + + FilariasisCampaign filariasisCampaign = new FilariasisCampaign(); + filariasisCampaign.setUserId(userId); + filariasisCampaign.setCreatedBy(userName); + filariasisCampaign.setUpdatedBy(userName); + + // Set start and end dates + filariasisCampaign.setStartDate(campaignDTO.getFields().getStartDate()); + filariasisCampaign.setEndDate(campaignDTO.getFields().getEndDate()); + + // Parse number of children + try { + String numberOfFamilies = (campaignDTO != null && campaignDTO.getFields() != null) + ? campaignDTO.getFields().getNumberOfFamilies() + : null; + + String numberOfIndividuals = (campaignDTO != null && campaignDTO.getFields() != null) + ? campaignDTO.getFields().getNumberOfIndividuals() + : null; + if (numberOfFamilies != null && !numberOfFamilies.trim().isEmpty()) { + try { + // parse as double first, then cast to int + double noDouble = Double.parseDouble(numberOfFamilies); + filariasisCampaign.setNumberOfFamilies((int) noDouble); + } catch (NumberFormatException e) { + filariasisCampaign.setNumberOfFamilies(0); // default 0 if invalid + } + } else { + filariasisCampaign.setNumberOfFamilies(0); + } + + if (numberOfIndividuals != null && !numberOfIndividuals.trim().isEmpty()) { + try { + // parse as double first, then cast to int + double noDouble = Double.parseDouble(numberOfIndividuals); + filariasisCampaign.setNumberOfIndividuals((int) noDouble); + } catch (NumberFormatException e) { + filariasisCampaign.setNumberOfIndividuals(0); // default 0 if invalid + } + } else { + filariasisCampaign.setNumberOfIndividuals(0); + } + } catch (NumberFormatException e) { + throw new IEMRException("Invalid number format for children: " + e.getMessage()); + } + + // Convert photos to base64 JSON array + FilariasisCampaignListDTO filariasisCampaignListDTO = campaignDTO.getFields(); + if(filariasisCampaignListDTO!=null){ + String photosJson = objectMapper.writeValueAsString(filariasisCampaignListDTO.getMdaPhotos()); + filariasisCampaign.setCampaignPhotos(photosJson); + + + } + + campaignPolioRequest.add(filariasisCampaign); + } + + if (!campaignPolioRequest.isEmpty()) { + List savedCampaigns = filariasisCampaignRepo.saveAll(campaignPolioRequest); + + savedCampaigns.forEach(filariasisCampaign -> { + checkMonthlyFilariasisIncentive(filariasisCampaign.getUserId(),filariasisCampaign.getStartDate(),filariasisCampaign.getEndDate()); + + });{ + + } + return savedCampaigns; + } + + throw new IEMRException("No valid campaign data to save"); + } + + + + @Override + public List getPolioCampaign(String token) throws IEMRException { + Integer userId = jwtUtil.extractUserId(token); + List polioCampaignDTOSResponse = new ArrayList<>(); + int page = 0; + int pageSize = 10; + Page campaignPolioPage; + do { + Pageable pageable = PageRequest.of(page, pageSize); + campaignPolioPage = pulsePolioCampaignRepo.findByUserId(userId, pageable); + for (PulsePolioCampaign campaignOrs : campaignPolioPage.getContent()) { + PolioCampaignResponseDTO dto = convertPolioToDTO(campaignOrs); + polioCampaignDTOSResponse.add(dto); + + } + page++; + } while (campaignPolioPage.hasNext()); + return polioCampaignDTOSResponse; + } + + @Override + public List getAllFilariasisCampaign(String token) throws IEMRException { + Integer userId = jwtUtil.extractUserId(token); + List filariasisResponseDTOS = new ArrayList<>(); + int page = 0; + int pageSize = 10; + Page campaignPolioPage; + do { + Pageable pageable = PageRequest.of(page, pageSize); + campaignPolioPage = filariasisCampaignRepo.findByUserId(userId, pageable); + for (FilariasisCampaign campaignOrs : campaignPolioPage.getContent()) { + FilariasisResponseDTO dto = convertFilariasisDTO(campaignOrs); + filariasisResponseDTOS.add(dto); + } + page++; + } while (campaignPolioPage.hasNext()); + return filariasisResponseDTOS; + } + + + private OrsCampaignResponseDTO convertOrsToDTO(CampaignOrs campaign) { + OrsCampaignResponseDTO dto = new OrsCampaignResponseDTO(); + OrsCampaignListResponseDTO orsCampaignListDTO = new OrsCampaignListResponseDTO(); + if (campaign.getCampaignPhotos() != null) { + ObjectMapper objectMapper = new ObjectMapper(); + List photosList = new ArrayList<>(); + + String photoStr = campaign.getCampaignPhotos(); + + if (photoStr != null && !photoStr.trim().isEmpty()) { + try { + // try JSON list + photosList = objectMapper.readValue( + photoStr, + new TypeReference>() {} + ); + } catch (Exception e) { + // fallback: single image + photosList.add(photoStr.trim()); + } + } + orsCampaignListDTO.setCampaignPhotos(photosList); + } + orsCampaignListDTO.setEndDate(campaign.getEndDate()); + orsCampaignListDTO.setStartDate(campaign.getStartDate()); + orsCampaignListDTO.setNumberOfFamilies(Double.valueOf(campaign.getNumberOfFamilies())); + dto.setId(campaign.getId()); + dto.setFields(orsCampaignListDTO); + + return dto; + } + + private PolioCampaignResponseDTO convertPolioToDTO(PulsePolioCampaign campaign) { + PolioCampaignResponseDTO dto = new PolioCampaignResponseDTO(); + PolioCampaignListResponseDTO polioCampaignListDTO = new PolioCampaignListResponseDTO(); + if (campaign.getCampaignPhotos() != null) { + List photosList = new ArrayList<>(); + + String photoStr = campaign.getCampaignPhotos(); + + if (photoStr != null && !photoStr.trim().isEmpty()) { + try { + // try JSON list + photosList = objectMapper.readValue( + photoStr, + new TypeReference>() {} + ); + } catch (Exception e) { + // fallback: single image + photosList.add(photoStr.trim()); + } + } + + polioCampaignListDTO.setCampaignPhotos(photosList); + } + polioCampaignListDTO.setEndDate(campaign.getEndDate()); + polioCampaignListDTO.setStartDate(campaign.getStartDate()); + polioCampaignListDTO.setNumberOfChildren(Double.valueOf(campaign.getNumberOfChildren())); + dto.setId(campaign.getId()); + dto.setFields(polioCampaignListDTO); + return dto; + } + + private FilariasisResponseDTO convertFilariasisDTO(FilariasisCampaign campaign) { + FilariasisResponseDTO dto = new FilariasisResponseDTO(); + FilariasisCampaignListResponseDTO filariasisCampaignListDTO = new FilariasisCampaignListResponseDTO(); + if (campaign.getCampaignPhotos() != null) { + List photosList = new ArrayList<>(); + String photoStr = campaign.getCampaignPhotos(); + + if (photoStr != null && !photoStr.trim().isEmpty()) { + try { + // try JSON list + photosList = objectMapper.readValue( + photoStr, + new TypeReference>() {} + ); + } catch (Exception e) { + // fallback: single image + photosList.add(photoStr.trim()); + } + } + + filariasisCampaignListDTO.setMdaPhotos(photosList); + } + filariasisCampaignListDTO.setEndDate(campaign.getEndDate()); + filariasisCampaignListDTO.setStartDate(campaign.getStartDate()); + Double numberOfIndividuals = null; + Double numberOfFamilies = null; + + if (campaign.getNumberOfIndividuals() != null) { + numberOfIndividuals = Double.valueOf(campaign.getNumberOfIndividuals()); + } + + if (campaign.getNumberOfFamilies() != null) { + numberOfFamilies = Double.valueOf(campaign.getNumberOfFamilies()); + } + + filariasisCampaignListDTO.setNumberOfIndividuals(numberOfIndividuals); + filariasisCampaignListDTO.setNumberOfFamilies(numberOfFamilies); + + dto.setFields(filariasisCampaignListDTO); + return dto; + } + private List parseBase64Json(String jsonString) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(jsonString, new TypeReference>() {}); + } catch (JsonProcessingException e) { + return Collections.emptyList(); + } + } + + private void checkMonthlyPulsePolioIncentive(Integer ashaId,LocalDate startDate,LocalDate endDate) { + + IncentiveActivity CHILD_MOBILIZATION_SESSIONS = incentivesRepo.findIncentiveMasterByNameAndGroup("PULSE_POLIO_SUPPORT", GroupName.ACTIVITY.getDisplayName()); + if (CHILD_MOBILIZATION_SESSIONS != null) { + addAshaIncentiveRecord(CHILD_MOBILIZATION_SESSIONS, ashaId,startDate,endDate); + } + + } + + private void checkMonthlyFilariasisIncentive(Integer ashaId,LocalDate startDate,LocalDate endDate) { + IncentiveActivity FILARIASIS_MEDICINE_DISTRIBUTION = incentivesRepo.findIncentiveMasterByNameAndGroup("FILARIASIS_MEDICINE_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); + if (FILARIASIS_MEDICINE_DISTRIBUTION != null) { + addAshaIncentiveRecord(FILARIASIS_MEDICINE_DISTRIBUTION, ashaId,startDate,endDate); + } + + } + + private void checkMonthlyPulseOrsDistribution(Integer ashaId,LocalDate startDate,LocalDate endDate) { + IncentiveActivity ORS_DISTRIBUTION = incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); + if (ORS_DISTRIBUTION != null) { + addAshaIncentiveRecord(ORS_DISTRIBUTION, ashaId,startDate,endDate); + } + + } + + private void addAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId,LocalDate startDate,LocalDate endDate) { + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + + Timestamp startOfMonth = Timestamp.valueOf(startDate.atStartOfDay()); + Timestamp endOfMonth = Timestamp.valueOf(endDate.atStartOfDay()); + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + 0L, + ashaId, + startOfMonth, + endOfMonth + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(timestamp); + record.setCreatedBy(userServiceRoleRepo.getUserNamedByUserId(ashaId)); + record.setStartDate(timestamp); + record.setEndDate(timestamp); + record.setUpdatedDate(timestamp); + record.setUpdatedBy(userServiceRoleRepo.getUserNamedByUserId(ashaId)); + record.setBenId(0L); + record.setAshaId(ashaId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } + +} + diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 8d23dd6b8..4903e1fc3 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -3,19 +3,28 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.ChildCareService; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; +import jakarta.persistence.EntityNotFoundException; import org.aspectj.weaver.ast.Or; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -75,6 +84,19 @@ public class ChildCareServiceImpl implements ChildCareService { @Autowired private OrsDistributionRepo orsDistributionRepo; + @Autowired + private IncentivePendingActivityRepository incentivePendingActivityRepository; + + @Autowired + private UserService userService; + + @Autowired + private IncentiveLogicService incentiveLogicService; + + @Autowired + private ANCVisitRepo ancVisitRepo; + @Autowired + private PNCVisitRepo pncVisitRepo; @Override @@ -82,6 +104,7 @@ public String registerHBYC(List hbycDTOs) { try { List hbycList = new ArrayList<>(); + hbycDTOs.forEach(it -> { HbycDTO hbycDTO = it.getFields(); hbycDTO.setVisit_date(it.getVisitDate()); @@ -90,14 +113,11 @@ public String registerHBYC(List hbycDTOs) { if (hbyc != null) { Long id = hbyc.getId(); - modelMapper.map(it, hbycDTO); hbyc.setId(id); hbyc.setUserId(userRepo.getUserIdByName(it.getUserName())); hbyc.setCreated_by(it.getUserName()); } else { hbyc = new HbycChildVisit(); - modelMapper.map(it, hbycDTO); - hbyc.setId(null); hbyc.setUserId(userRepo.getUserIdByName(it.getUserName())); hbyc.setCreated_by(it.getUserName()); hbyc.setBeneficiaryId(it.getBeneficiaryId()); @@ -134,14 +154,17 @@ public String registerHBYC(List hbycDTOs) { hbyc.setMcp_card_images(hbycDTO.getMcp_card_images()); } + hbycList.add(hbyc); }); hbycRepo.saveAll(hbycList); + logger.info("Total records to save : {}", hbycList.size()); checkAndAddHbyncIncentives(hbycList); return "no of hbyc details saved: " + hbycDTOs.size(); } catch (Exception e) { - logger.info("error while saving hbyc details: " + e.getMessage()); + logger.error("error while saving hbyc details", e); + } return null; } @@ -210,47 +233,62 @@ public List getHbycRecords(GetBenRequestHandler dto) { @Override public List getHBNCDetails(GetBenRequestHandler dto) { List result = new ArrayList<>(); + int page = 0; + int size = 20; + + Page visitPage; try { - List hbncVisits = hbncVisitRepo.findByAshaId(dto.getAshaId()); + do { + Pageable pageable = PageRequest.of(page, size, Sort.by("id").descending()); - for (HbncVisit visit : hbncVisits) { - HbncVisitResponseDTO responseDTO = new HbncVisitResponseDTO(); - responseDTO.setId(visit.getId()); - responseDTO.setBeneficiaryId(visit.getBeneficiaryId()); // Update with actual value - responseDTO.setHouseHoldId(visit.getHouseHoldId()); // Update with actual value - responseDTO.setVisitDate(visit.getVisit_date().split(" ")[0]); // Format visit.getVisitDate() + visitPage = hbncVisitRepo.findByAshaId(dto.getAshaId(), pageable); - // Convert all fields to Map - Map fields = new HashMap<>(); - addIfValid(fields, "visit_day", visit.getVisit_day()); - addIfValid(fields, "visit_date", visit.getVisit_date()); - addIfValid(fields, "due_date", visit.getDue_date()); - addIfValid(fields, "is_baby_alive", convert(visit.getIs_baby_alive())); - addIfValid(fields, "date_of_death", visit.getDate_of_death()); - addIfValid(fields, "reason_for_death", visit.getReasonForDeath()); - addIfValid(fields, "place_of_death", visit.getPlace_of_death()); - addIfValid(fields, "other_place_of_death", visit.getOther_place_of_death()); - addIfValid(fields, "baby_weight", visit.getBaby_weight()); - addIfValid(fields, "urine_passed", convert(visit.getUrine_passed())); - addIfValid(fields, "stool_passed", convert(visit.getStool_passed())); - addIfValid(fields, "diarrhoea", convert(visit.getDiarrhoea())); - addIfValid(fields, "vomiting", convert(visit.getVomiting())); - addIfValid(fields, "convulsions", convert(visit.getConvulsions())); - addIfValid(fields, "activity", visit.getActivity()); - addIfValid(fields, "sucking", visit.getSucking()); - addIfValid(fields, "breathing", visit.getBreathing()); - addIfValid(fields, "chest_indrawing", visit.getChest_indrawing()); - addIfValid(fields, "temperature", visit.getTemperature()); - addIfValid(fields, "jaundice", convert(visit.getJaundice())); - addIfValid(fields, "umbilical_stump", visit.getUmbilical_stump()); - addIfValid(fields, "discharged_from_sncu", convert(visit.getDischarged_from_sncu())); - addIfValid(fields, "discharge_summary_upload", visit.getDischarge_summary_upload()); - - // Add more fields as required - - responseDTO.setFields(fields); - result.add(responseDTO); - } + List hbncVisits = visitPage.getContent(); + + for (HbncVisit visit : hbncVisits) { + HbncVisitResponseDTO responseDTO = new HbncVisitResponseDTO(); + responseDTO.setId(visit.getId()); + responseDTO.setBeneficiaryId(visit.getBeneficiaryId()); // Update with actual value + responseDTO.setHouseHoldId(visit.getHouseHoldId()); // Update with actual value + responseDTO.setVisitDate(visit.getVisit_date().split(" ")[0]); // Format visit.getVisitDate() + + // Convert all fields to Map + Map fields = new HashMap<>(); + if(visit.getVisit_day()!=null){ + addIfValid(fields, "visit_day", visit.getVisit_day()); + + } + addIfValid(fields, "due_date", visit.getDue_date()); + addIfValid(fields, "is_baby_alive", convert(visit.getIs_baby_alive())); + addIfValid(fields, "date_of_death", visit.getDate_of_death()); + addIfValid(fields, "reason_for_death", visit.getReasonForDeath()); + addIfValid(fields, "place_of_death", visit.getPlace_of_death()); + addIfValid(fields, "other_place_of_death", visit.getOther_place_of_death()); + addIfValid(fields, "baby_weight", visit.getBaby_weight()); + addIfValid(fields, "urine_passed", convert(visit.getUrine_passed())); + addIfValid(fields, "stool_passed", convert(visit.getStool_passed())); + addIfValid(fields, "diarrhoea", convert(visit.getDiarrhoea())); + addIfValid(fields, "vomiting", convert(visit.getVomiting())); + addIfValid(fields, "convulsions", convert(visit.getConvulsions())); + addIfValid(fields, "activity", visit.getActivity()); + addIfValid(fields, "sucking", visit.getSucking()); + addIfValid(fields, "breathing", visit.getBreathing()); + addIfValid(fields, "chest_indrawing", visit.getChest_indrawing()); + addIfValid(fields, "temperature", visit.getTemperature()); + addIfValid(fields, "jaundice", convert(visit.getJaundice())); + addIfValid(fields, "umbilical_stump", visit.getUmbilical_stump()); + addIfValid(fields, "discharged_from_sncu", convert(visit.getDischarged_from_sncu())); + addIfValid(fields, "discharge_summary_upload", visit.getDischarge_summary_upload()); + + // Add more fields as required + + responseDTO.setFields(fields); + result.add(responseDTO); + + } + page++; + + }while (visitPage.hasNext()); } catch (Exception e) { logger.error("Error in getHBNCDetails: ", e); @@ -272,8 +310,8 @@ private String convert(Boolean value) { } private Boolean convertBollen(String value) { - if (value.equals("Yes")) { - return true; + if (value != null && !value.isEmpty()) { + return value.equalsIgnoreCase("Yes"); } else { return false; } @@ -292,7 +330,7 @@ private String convert(String value) { @Override - public String saveHBNCDetails(List hbncRequestDTOs) { + public String saveHBNCDetails(List hbncRequestDTOs, Integer userId) { try { List hbncList = new ArrayList<>(); @@ -322,7 +360,7 @@ public String saveHBNCDetails(List hbncRequestDTOs) { hbncVisitRepo.saveAll(hbncList); - checkAndAddHbncIncentives(hbncList); + checkAndAddHbncIncentives(hbncList, userId); logger.info("HBNC details saved"); @@ -342,11 +380,18 @@ public List getChildVaccinationDetails(GetBenRequestHandler List result = new ArrayList<>(); vaccinationDetails.forEach(childVaccination -> { ChildVaccinationDTO vaccinationDTO = mapper.convertValue(childVaccination, ChildVaccinationDTO.class); - BigInteger benId = beneficiaryRepo.getBenIdFromRegID(childVaccination.getBeneficiaryRegId()); - vaccinationDTO.setBeneficiaryId(benId.longValue()); + if(childVaccination.getBeneficiaryRegId()!=null){ + BigInteger benId = beneficiaryRepo.getBenIdFromRegID(childVaccination.getBeneficiaryRegId()); + vaccinationDTO.setBeneficiaryId(benId.longValue()); + + } + if(!vaccinationDetails.isEmpty()){ + checkAndAddIncentives(vaccinationDetails); + + } + result.add(vaccinationDTO); - checkAndAddIncentives(vaccinationDetails); }); return result; } catch (Exception e) { @@ -378,7 +423,10 @@ public String saveChildVaccinationDetails(List childVaccina vaccinationList.add(vaccination); }); childVaccinationRepo.saveAll(vaccinationList); - checkAndAddIncentives(vaccinationList); + if(!vaccinationList.isEmpty()){ + checkAndAddIncentives(vaccinationList); + + } logger.info("Child Vaccination details saved"); return "No of child vaccination details saved: " + vaccinationList.size(); } catch (Exception e) { @@ -437,7 +485,7 @@ public List getAllChildVaccines(String category) { } @Override - public String saveSamDetails(List samRequest) { + public String saveSamDetails(List samRequest, Integer userId, String userName) { try { List vaccinationList = new ArrayList<>(); @@ -458,11 +506,9 @@ public String saveSamDetails(List samRequest) { samVisit.setVisitDate(LocalDate.parse(samDTO.getVisitDate())); // ✅ Common user details - samVisit.setUserId(userRepo.getUserIdByName(jwtUtil.getUserNameFromStorage())); - samVisit.setCreatedBy(jwtUtil.getUserNameFromStorage()); - if (samVisit.getCreatedBy() == null) { - samVisit.setCreatedBy(jwtUtil.getUserNameFromStorage()); - } + samVisit.setUserId(userId); + samVisit.setCreatedBy(userName); + // ✅ Field mapping samVisit.setMuac(samDTO.getFields().getMuac()); @@ -492,7 +538,7 @@ public String saveSamDetails(List samRequest) { samVisitRepository.saveAll(vaccinationList); // ✅ Handle incentive logic - checkAndAddSamVisitNRCReferalIncentive(vaccinationList); + checkAndAddSamVisitNRCReferalIncentive(vaccinationList, userId); return "Saved/Updated " + samRequest.size() + " SAM visit records successfully"; } catch (Exception e) { @@ -532,8 +578,10 @@ public List getSamVisitsByBeneficiary(GetBenRequestHandler reque // ✅ Final Visit Label dto.setVisitLabel("Visit-" + visitNo); - - dto.setMuac(Double.parseDouble(entity.getMuac())); + String muacVal = entity.getMuac(); + dto.setMuac((muacVal != null && !muacVal.trim().isEmpty()) + ? Double.parseDouble(muacVal.trim()) + : 0.0); dto.setWeightForHeightStatus(entity.getWeightForHeightStatus()); dto.setIsChildReferredNrc(entity.getIsChildReferredNrc()); dto.setIsChildAdmittedNrc(entity.getIsChildAdmittedNrc()); @@ -545,7 +593,8 @@ public List getSamVisitsByBeneficiary(GetBenRequestHandler reque try { List followUpDates = mapper.readValue( entity.getFollowUpVisitDate(), - new TypeReference>() {}); + new TypeReference>() { + }); dto.setFollowUpVisitDate(followUpDates); } catch (JsonProcessingException e) { throw new RuntimeException(e); @@ -560,13 +609,13 @@ public List getSamVisitsByBeneficiary(GetBenRequestHandler reque } - return samResponseListDTO; } @Override public String saveOrsDistributionDetails(List orsDistributionDTOS) { try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); List orsDistributionList = new ArrayList<>(); orsDistributionDTOS.forEach(orsDistributionDTO -> { @@ -574,28 +623,31 @@ public String saveOrsDistributionDetails(List orsDistributio orsDistribution.setId(orsDistributionDTO.getId()); orsDistribution.setBeneficiaryId(orsDistributionDTO.getBeneficiaryId()); orsDistribution.setNumOrsPackets(orsDistributionDTO.getFields().getNum_ors_packets().toString()); - orsDistribution.setChildCount(orsDistributionDTO.getFields().getNum_under5_children().toString()); + if (orsDistributionDTO.getFields().getNum_under5_children() != null) { + orsDistribution.setChildCount(orsDistributionDTO.getFields().getNum_under5_children().toString()); + + } orsDistribution.setHouseholdId(orsDistributionDTO.getHouseHoldId()); orsDistribution.setUserId(userRepo.getUserIdByName(orsDistributionDTO.getUserName())); - orsDistribution.setVisitDate(LocalDate.parse(orsDistributionDTO.getFields().getVisit_date(),formatter)); + orsDistribution.setVisitDate(LocalDate.parse(orsDistributionDTO.getFields().getVisit_date(), formatter)); orsDistributionList.add(orsDistribution); }); - logger.info("orsList"+orsDistributionList.size()); - if(!orsDistributionList.isEmpty()){ + logger.info("orsList" + orsDistributionList.size()); + if (!orsDistributionList.isEmpty()) { orsDistributionRepo.saveAll(orsDistributionList); checkAndAddOrdDistributionIncentive(orsDistributionList); return "Saved " + orsDistributionList.size() + " ORS visit records successfully"; } - }catch (Exception e){ - logger.error("ORS Error"+e); + } catch (Exception e) { + logger.error("ORS Error" + e); } - return null ; + return null; } @@ -604,23 +656,28 @@ public List getOrdDistrubtion(GetBenRequestHandler r List entities = orsDistributionRepo.findByUserId(request.getAshaId()); List orsDistributionResponseDTOSList = new ArrayList<>(); - for(OrsDistribution orsDistribution: entities){ + for (OrsDistribution orsDistribution : entities) { OrsDistributionResponseDTO orsDistributionResponseDTO = new OrsDistributionResponseDTO(); OrsDistributionResponseListDTO orsDistributionResponseListDTO = new OrsDistributionResponseListDTO(); orsDistributionResponseDTO.setId(orsDistribution.getId()); orsDistributionResponseDTO.setBeneficiaryId(orsDistribution.getBeneficiaryId()); orsDistributionResponseDTO.setHouseHoldId(orsDistribution.getHouseholdId()); - orsDistributionResponseListDTO.setNum_ors_packets(orsDistribution.getNumOrsPackets().toString()); - orsDistributionResponseListDTO.setNum_under5_children(orsDistribution.getChildCount().toString()); + if (orsDistribution.getNumOrsPackets() != null) { + orsDistributionResponseListDTO.setNum_ors_packets(orsDistribution.getNumOrsPackets().toString()); + + } + if (orsDistribution.getChildCount() != null) { + orsDistributionResponseListDTO.setNum_under5_children(orsDistribution.getChildCount().toString()); + + } orsDistributionResponseDTO.setFields(orsDistributionResponseListDTO); orsDistributionResponseDTO.setVisitDate(parseDate(orsDistribution.getVisitDate().toString()).toString()); orsDistributionResponseDTOSList.add(orsDistributionResponseDTO); - } - return orsDistributionResponseDTOSList; + return orsDistributionResponseDTOSList; } @@ -634,30 +691,75 @@ private LocalDate parseDate(String dateStr) { for (DateTimeFormatter f : formatters) { try { return LocalDate.parse(dateStr, f); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } throw new DateTimeParseException("Invalid date format: " + dateStr, dateStr, 0); } + @Override - public List saveAllIfa(List dtoList) { - return dtoList.stream() - .map(this::mapToEntity) + public List saveAllIfa(List dtoList, Integer userId) { + List savedList = dtoList.stream() + .map(dto -> mapToEntity(dto, userId)) .map(ifaDistributionRepository::save) .toList(); - } + // incentive generate + savedList.forEach(data -> { + Timestamp visitTimestamp = + Timestamp.valueOf(data.getIfaProvisionDate().atStartOfDay()); + if(data.getIfaBottleCount().equals("10.0")){ + incentiveLogicService.incentiveForGiveingIFA( + data.getBeneficiaryId(), + visitTimestamp, + visitTimestamp, + data.getUserId() + ); + } + + }); + + return savedList; + } @Override public List getByBeneficiaryId(GetBenRequestHandler requestHandler) { - return ifaDistributionRepository.findByUserId(requestHandler.getAshaId()).stream() - .map(this::mapToDTO) + + return ifaDistributionRepository.findByUserId(requestHandler.getAshaId()) + .stream() + .map(data -> { + + try { + if ("10.0".equals(data.getIfaBottleCount())) { + + Timestamp visitTimestamp = + Timestamp.valueOf(data.getIfaProvisionDate().atStartOfDay()); + + incentiveLogicService.incentiveForGiveingIFA( + data.getBeneficiaryId(), + visitTimestamp, + visitTimestamp, + data.getUserId() + ); + } + } catch (Exception e) { + logger.error( + "Error while processing IFA incentive for beneficiaryId: {}", + data.getBeneficiaryId(), + e + ); + } + + return mapToDTO(data); + }) .toList(); } + // 🔁 Entity → DTO (date formatted as dd-MM-yyyy) private IfaDistributionDTO mapToDTO(IfaDistribution entity) { - final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); IfaDistributionDTO dto = new IfaDistributionDTO(); @@ -679,7 +781,7 @@ private IfaDistributionDTO mapToDTO(IfaDistribution entity) { } // 🔄 Helper method to convert DTO → Entity - private IfaDistribution mapToEntity(IfaDistributionDTO dto) { + private IfaDistribution mapToEntity(IfaDistributionDTO dto, Integer userId) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); IfaDistribution entity = new IfaDistribution(); @@ -688,7 +790,7 @@ private IfaDistribution mapToEntity(IfaDistributionDTO dto) { entity.setHouseHoldId(dto.getHouseHoldId()); entity.setFormId(dto.getFormId()); entity.setVisitDate(dto.getVisitDate()); - entity.setUserId(userRepo.getUserIdByName(jwtUtil.getUserNameFromStorage())); + entity.setUserId(userId); if (dto.getFields() != null) { if (dto.getFields().getIfa_provision_date() != null) { @@ -708,20 +810,25 @@ private IfaDistribution mapToEntity(IfaDistributionDTO dto) { return entity; } - private void checkAndAddSamVisitNRCReferalIncentive(List samVisits){ + private void checkAndAddSamVisitNRCReferalIncentive(List samVisits, Integer userId) { samVisits.forEach(samVisit -> { IncentiveActivity samreferralnrcActivityAm = incentivesRepo.findIncentiveMasterByNameAndGroup("SAM_REFERRAL_NRC", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity samreferralnrcActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("SAM_REFERRAL_NRC", GroupName.ACTIVITY.getDisplayName()); - if(samreferralnrcActivityAm!=null){ - if(samVisit.getIsChildReferredNrc().equals("Yes")){ - createIncentiveRecordforSamReferalToNrc(samVisit,samVisit.getBeneficiaryId(),samreferralnrcActivityAm,jwtUtil.getUserNameFromStorage()); + IncentiveActivity samreferralnrcActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("SAM_REFERRAL_NRC", GroupName.ACTIVITY.getDisplayName()); + if (userService.getUserDetail(userId).getStateId().equals(StateCode.AM.getStateCode())) { + + if (samreferralnrcActivityAm != null) { + if (samVisit.getIsChildReferredNrc().equals("Yes")) { + createIncentiveRecordforSamReferalToNrc(samVisit, samVisit.getBeneficiaryId(), samreferralnrcActivityAm, samVisit.getCreatedBy()); + } } } - if(samreferralnrcActivityCH!=null){ - if(samVisit.getIsChildReferredNrc().equals("Yes")){ - createIncentiveRecordforSamReferalToNrc(samVisit,samVisit.getBeneficiaryId(),samreferralnrcActivityCH,jwtUtil.getUserNameFromStorage()); + if (userService.getUserDetail(userId).getStateId().equals(StateCode.CG.getStateCode())) { + if (samreferralnrcActivityCH != null) { + if (samVisit.getIsChildReferredNrc().equals("Yes")) { + createIncentiveRecordforSamReferalToNrc(samVisit, samVisit.getBeneficiaryId(), samreferralnrcActivityCH, samVisit.getCreatedBy()); + } } } @@ -729,20 +836,14 @@ private void checkAndAddSamVisitNRCReferalIncentive(List samVisits){ }); } - private void checkAndAddOrdDistributionIncentive(List orsDistributionList){ + + private void checkAndAddOrdDistributionIncentive(List orsDistributionList) { orsDistributionList.forEach(orsDistribution -> { IncentiveActivity orsPacketActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity orsPacketActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); - if(orsPacketActivityAM!=null){ - if(orsDistribution.getNumOrsPackets()!=null){ - createIncentiveRecordforOrsDistribution(orsDistribution,orsDistribution.getBeneficiaryId(),orsPacketActivityAM,userRepo.getUserNamedByUserId(orsDistribution.getUserId()),false); - } - } - - if(orsPacketActivityCH!=null){ - if(orsDistribution.getNumOrsPackets()!=null){ - createIncentiveRecordforOrsDistribution(orsDistribution,orsDistribution.getBeneficiaryId(),orsPacketActivityCH,userRepo.getUserNamedByUserId(orsDistribution.getUserId()),true); + if (orsPacketActivityAM != null) { + if (orsDistribution.getNumOrsPackets() != null) { + createIncentiveRecordforOrsDistribution(orsDistribution, orsDistribution.getBeneficiaryId(), orsPacketActivityAM, userRepo.getUserNamedByUserId(orsDistribution.getUserId()), false); } } @@ -752,74 +853,142 @@ private void checkAndAddOrdDistributionIncentive(List orsDistr } private void checkAndAddHbyncIncentives(List hbycList) { - IncentiveActivity hbync15MonethVisitActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity hbyncVisitActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.CHILD_HEALTH.getDisplayName()); - + if(!hbycList.isEmpty()){ + Integer userId = hbycList.get(0).getUserId(); + Integer stateId = userService.getUserDetail(userId).getStateId(); - IncentiveActivity hbyncOrsPacketActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity hbync15MonethVisitActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity hbyncVisitActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.CHILD_HEALTH.getDisplayName()); - hbycList.forEach(hbyc -> { - Set eligibleHbycVisits = Set.of("3 Months", "6 Months", "9 Months", "12 Months", "15 Months"); - if (hbyncVisitActivity != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { - createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncVisitActivity, hbyc.getCreated_by()); - } + IncentiveActivity hbyncLactatingIronPacketActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("LACTATING_MOTHERS_HOME_VISIT", GroupName.ACTIVITY.getDisplayName()); - if (hbync15MonethVisitActivityCH != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { - createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbync15MonethVisitActivityCH, hbyc.getCreated_by()); - } + hbycList.forEach(hbyc -> { + Set eligibleHbycVisits = Set.of("3 Months", "6 Months", "9 Months", "12 Months", "15 Months"); + if(stateId.equals(StateCode.AM.getStateCode())){ + if (hbyncVisitActivity != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncVisitActivity, hbyc.getCreated_by()); + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ + if (hbync15MonethVisitActivityCH != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbync15MonethVisitActivityCH, hbyc.getCreated_by()); + } + if(hbyc.getIfa_given() && eligibleHbycVisits.contains(hbyc.getVisit_day())){ + if(hbyncLactatingIronPacketActivityCH!=null){ + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncLactatingIronPacketActivityCH, hbyc.getCreated_by()); + } + } + } - if (hbyncOrsPacketActivityCH != null) { - if (hbyc.getOrs_given()) { - createIncentiveRecordforHbyncOrsDistribution(hbyc, hbyc.getBeneficiaryId(), hbyncOrsPacketActivityCH, hbyc.getCreated_by()); - } - } + }); + } - }); } - private void checkAndAddHbncIncentives(List hbncVisits) { + private void checkAndAddHbncIncentives(List hbncVisits, Integer userId) { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + List pncVisits = pncVisitRepo.getPNCForPW(userRepo.getUserNamedByUserId(userId)); + List ancVisits = ancVisitRepo.getANCForPW(userRepo.getUserNamedByUserId(userId)); hbncVisits.forEach(hbncVisit -> { - boolean isVisitDone = List.of("1st Day", "3rd Day", "7th Day", "42nd Day") - .stream() - .allMatch(hbncVisits::contains); - - GroupName.setIsCh(false); Long benId = hbncVisit.getBeneficiaryId(); - if (hbncVisit.getVisit_day().equals("42nd Day")) { - IncentiveActivity visitActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.ACTIVITY.getDisplayName()); + if (stateCode.equals(StateCode.AM.getStateCode())) { + if (hbncVisit.getVisit_day().equals("42nd Day")) { + IncentiveActivity visitActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.CHILD_HEALTH.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityAM, "HBNC_0_42_DAYS"); - createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HBNC_0_42_DAYS_CH"); + createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityAM, "HBNC_0_42_DAYS"); - } - logger.info("getDischarged_from_sncu" + hbncVisit.getDischarged_from_sncu()); + } + + pncVisits.forEach(pncVisit -> { + Long hbncHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(hbncVisit.getBeneficiaryId())).get(0).getHouseoldId(); + Long houseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(pncVisit.getBenId())).get(0).getHouseoldId(); + + if (hbncHouseHoldId.equals(houseHoldId)) { + if (hbncVisit.getVisit_day().equals("42th Day")) { + if (!ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { + if (ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getIsHrpConfirmed()) { + IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); + createIncentiveRecordforHbncVisit(hbncVisit, pncVisit.getBenId(), visitActivityCH, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); + } + } + if (!pncVisitRepo.findByBenId(pncVisit.getBenId()).isEmpty()) { + if (!pncVisitRepo.findByBenId(pncVisit.getBenId()).get(0).getMotherDangerSign().isEmpty()) { + IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); + createIncentiveRecordforHbncVisit(hbncVisit, pncVisit.getBenId(), visitActivityCH, "HIGH_RISK_POSTPARTUM_CARE"); + } + } + } + } + }); + + ancVisits.forEach(ancVisit -> { + Long hbncHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(hbncVisit.getBeneficiaryId())).get(0).getHouseoldId(); + Long ancHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(ancVisit.getBenId())).get(0).getHouseoldId(); + + if (hbncHouseHoldId.equals(ancHouseHoldId)) { + if (hbncVisit.getVisit_day().equals("42th Day")) { + if (!ancVisitRepo.findByBenId(ancVisit.getBenId()).isEmpty()) { + if (ancVisitRepo.findByBenId(ancVisit.getBenId()).get(0).getIsHrpConfirmed()) { + IncentiveActivity visitActivityANC = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); + createIncentiveRecordforHbncVisit(hbncVisit, ancVisit.getBenId(), visitActivityANC, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); + } + } + } + } + }); + + logger.info("getDischarged_from_sncu" + hbncVisit.getDischarged_from_sncu()); + + if (hbncVisit.getVisit_day().equals("42nd Day") && hbncVisit.getDischarged_from_sncu() && hbncVisit.getBaby_weight() <= 2.5) { + IncentiveActivity babyDisChargeSNCUAActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("SNCU_LBW_FOLLOWUP", GroupName.CHILD_HEALTH.getDisplayName()); - if (hbncVisit.getVisit_day().equals("42nd Day") && hbncVisit.getDischarged_from_sncu() && hbncVisit.getBaby_weight() <=2.5) { - IncentiveActivity babyDisChargeSNCUAActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("SNCU_LBW_FOLLOWUP", GroupName.CHILD_HEALTH.getDisplayName()); + createIncentiveRecordforHbncVisit(hbncVisit, benId, babyDisChargeSNCUAActivity, "SNCU_LBW_FOLLOWUP"); - createIncentiveRecordforHbncVisit(hbncVisit, benId, babyDisChargeSNCUAActivity, "SNCU_LBW_FOLLOWUP"); + } + logger.info("getIs_baby_alive" + hbncVisit.getIs_baby_alive()); + if (!hbncVisit.getIs_baby_alive()) { + IncentiveActivity isChildDeathActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); + createIncentiveRecordforHbncVisit(hbncVisit, benId, isChildDeathActivity, "CHILD_DEATH_REPORTING"); + } } - logger.info("getIs_baby_alive" + hbncVisit.getIs_baby_alive()); - if (!hbncVisit.getIs_baby_alive()) { - IncentiveActivity isChildDeathActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, benId, isChildDeathActivity, "CHILD_DEATH_REPORTING"); + if (stateCode.equals(StateCode.CG.getStateCode())) { + if (hbncVisit.getVisit_day().equals("42th Day")) { + if (!ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { + if (ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getIsHrpConfirmed() && pncVisitRepo.findByBenId(hbncVisit + .getBeneficiaryId()).get(0).getPncPeriod().toString().equals("42")) { + IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); + + } + } + if (!pncVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { + if (!pncVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getMotherDangerSign().isEmpty() && pncVisitRepo.findByBenId(hbncVisit + .getBeneficiaryId()).get(0).getPncPeriod().toString().equals("42")) { + IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HIGH_RISK_POSTPARTUM_CARE"); + + } + } + + } } @@ -830,59 +999,184 @@ private void checkAndAddHbncIncentives(List hbncVisits) { private void checkAndAddIncentives(List vaccinationList) { + String createdBy = vaccinationList.get(0).getCreatedBy(); - + Integer userId = userRepo.getUserIdByName(createdBy); + Integer stateId = userService.getUserDetail(userId).getStateId(); vaccinationList.forEach(vaccination -> { - Long benId = beneficiaryRepo.getBenIdFromRegID(vaccination.getBeneficiaryRegId()).longValue(); - Integer userId = userRepo.getUserIdByName(vaccination.getCreatedBy()); - Integer immunizationServiceId = getImmunizationServiceIdForVaccine(vaccination.getVaccineId().shortValue()); - if (immunizationServiceId < 6) { - IncentiveActivity immunizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FULL_IMMUNIZATION_0_1", GroupName.IMMUNIZATION.getDisplayName()); - IncentiveActivity immunizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FULL_IMMUNIZATION_0_1", GroupName.ACTIVITY.getDisplayName()); - - - if (immunizationActivityAM != null && childVaccinationRepo.getFirstYearVaccineCountForBenId(vaccination.getBeneficiaryRegId()) - .equals(childVaccinationRepo.getFirstYearVaccineCount())) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivityAM); + Long benId= null; + if(vaccination.getBeneficiaryRegId()!=null){ + BigInteger benIdObj = beneficiaryRepo.getBenIdFromRegID(vaccination.getBeneficiaryRegId()); + if (benIdObj != null) { + benId = benIdObj.longValue(); } - if (immunizationActivityCH != null && childVaccinationRepo.getFirstYearVaccineCountForBenId(vaccination.getBeneficiaryRegId()) - .equals(childVaccinationRepo.getFirstYearVaccineCount())) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivityCH); + Integer immunizationServiceId = getImmunizationServiceIdForVaccine(vaccination.getVaccineId().shortValue()); + if (immunizationServiceId < 6) { + + Integer completedVaccines = + childVaccinationRepo.getEligibleFirstYearVaccines( + vaccination.getBeneficiaryRegId()); + + + logger.info( + "FULL_IMMUNIZATION_0_1 :: BeneficiaryRegId={}, Vaccine={}, VaccineId={}, CompletedVaccines={}, StateId={}", + vaccination.getBeneficiaryRegId(), + vaccination.getVaccineName(), + vaccination.getVaccineId(), + completedVaccines, + stateId + ); + + IncentiveActivity immunizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FULL_IMMUNIZATION_0_1", + GroupName.IMMUNIZATION.getDisplayName()); + + IncentiveActivity immunizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FULL_IMMUNIZATION_0_1", + GroupName.ACTIVITY.getDisplayName()); + +// Required vaccines = 8 + if (completedVaccines != null && completedVaccines == 8) { + + logger.info( + "Beneficiary {} completed all required first year vaccines.", + vaccination.getBeneficiaryRegId()); + + if (stateId.equals(StateCode.AM.getStateCode()) + && immunizationActivityAM != null) { + + logger.info( + "Creating Assam FULL_IMMUNIZATION_0_1 incentive for BeneficiaryRegId={}", + vaccination.getBeneficiaryRegId()); + + createIncentiveRecord( + vaccination, + benId, + userId, + immunizationActivityAM); + } + + if (stateId.equals(StateCode.CG.getStateCode()) + && immunizationActivityCH != null) { + + logger.info( + "Creating Chhattisgarh FULL_IMMUNIZATION_0_1 incentive for BeneficiaryRegId={}", + vaccination.getBeneficiaryRegId()); + + createIncentiveRecord( + vaccination, + benId, + userId, + immunizationActivityCH); + } + + } else { + + logger.info( + "BeneficiaryRegId={} not eligible for FULL_IMMUNIZATION_0_1. CompletedVaccines={}/8", + vaccination.getBeneficiaryRegId(), + completedVaccines + ); + } + + } else if (immunizationServiceId == 7) { + + IncentiveActivity immunizationActivity2AM = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "COMPLETE_IMMUNIZATION_1_2", + GroupName.IMMUNIZATION.getDisplayName()); + + IncentiveActivity immunizationActivity2CH = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "COMPLETE_IMMUNIZATION_1_2", + GroupName.ACTIVITY.getDisplayName()); + + Integer completedVaccines = + childVaccinationRepo.getEligibleSecondYearVaccines( + vaccination.getBeneficiaryRegId()); + + logger.info( + "COMPLETE_IMMUNIZATION_1_2 :: BeneficiaryRegId={}, Vaccine={}, VaccineId={}, CompletedVaccines={}", + vaccination.getBeneficiaryRegId(), + vaccination.getVaccineName(), + vaccination.getVaccineId(), + completedVaccines + ); + + // Required vaccines count = 3 + if (completedVaccines != null && completedVaccines == 3) { + + logger.info( + "Beneficiary {} completed all required second year vaccines.", + vaccination.getBeneficiaryRegId()); + if(userService.getUserDetail(userId).getStateId().equals(StateCode.AM.getStateCode())) { + + if (immunizationActivity2AM != null) { + + logger.info( + "Creating IMMUNIZATION incentive for BeneficiaryRegId={}", + vaccination.getBeneficiaryRegId()); + + createIncentiveRecord( + vaccination, + benId, + userId, + immunizationActivity2AM); + } + } + if(userService.getUserDetail(userId).getStateId().equals(StateCode.CG.getStateCode())) { + + if (immunizationActivity2CH != null) { + + logger.info( + "Creating ACTIVITY incentive for BeneficiaryRegId={}", + vaccination.getBeneficiaryRegId()); + + createIncentiveRecord( + vaccination, + benId, + userId, + immunizationActivity2CH); + } + } + + } else { + + logger.info( + "BeneficiaryRegId={} not eligible. CompletedVaccines={}/3", + vaccination.getBeneficiaryRegId(), + completedVaccines); + } } - } else if (immunizationServiceId == 7) { - IncentiveActivity immunizationActivity2AM = - incentivesRepo.findIncentiveMasterByNameAndGroup("COMPLETE_IMMUNIZATION_1_2", GroupName.IMMUNIZATION.getDisplayName()); - IncentiveActivity immunizationActivity2CH = - incentivesRepo.findIncentiveMasterByNameAndGroup("COMPLETE_IMMUNIZATION_1_2", GroupName.ACTIVITY.getDisplayName()); - if (immunizationActivity2AM != null && childVaccinationRepo.getSecondYearVaccineCountForBenId(vaccination.getBeneficiaryRegId()) - .equals(childVaccinationRepo.getSecondYearVaccineCount())) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivity2AM); + IncentiveActivity immunizationActivity5AM = + incentivesRepo.findIncentiveMasterByNameAndGroup("DPT_IMMUNIZATION_5_YEARS", GroupName.IMMUNIZATION.getDisplayName()); + if(userService.getUserDetail(userId).getStateId().equals(StateCode.AM.getStateCode())) { + + if (immunizationActivity5AM != null && childVaccinationRepo.checkDptVaccinatedUser(vaccination.getBeneficiaryRegId()) == 1) { + createIncentiveRecord(vaccination, benId, userId, immunizationActivity5AM); + } } - if (immunizationActivity2CH != null && childVaccinationRepo.getSecondYearVaccineCountForBenId(vaccination.getBeneficiaryRegId()) - .equals(childVaccinationRepo.getSecondYearVaccineCount())) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivity2CH); + + IncentiveActivity immunizationActivity5CH = + incentivesRepo.findIncentiveMasterByNameAndGroup("DPT_IMMUNIZATION_5_YEARS", GroupName.ACTIVITY.getDisplayName()); + if(userService.getUserDetail(userId).getStateId().equals(StateCode.CG.getStateCode())) { + + if (immunizationActivity5CH != null && childVaccinationRepo.checkDptVaccinatedUser(vaccination.getBeneficiaryRegId()) == 1) { + createIncentiveRecord(vaccination, benId, userId, immunizationActivity5CH); + } } - } - IncentiveActivity immunizationActivity5AM = - incentivesRepo.findIncentiveMasterByNameAndGroup("DPT_IMMUNIZATION_5_YEARS", GroupName.IMMUNIZATION.getDisplayName()); - if (immunizationActivity5AM != null && childVaccinationRepo.checkDptVaccinatedUser(vaccination.getBeneficiaryRegId()) == 1) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivity5AM); - } - IncentiveActivity immunizationActivity5CH = - incentivesRepo.findIncentiveMasterByNameAndGroup("DPT_IMMUNIZATION_5_YEARS", GroupName.ACTIVITY.getDisplayName()); - if (immunizationActivity5CH != null && childVaccinationRepo.checkDptVaccinatedUser(vaccination.getBeneficiaryRegId()) == 1) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivity5CH); } + }); } private void createIncentiveRecord(ChildVaccination vaccination, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), vaccination.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), vaccination.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); @@ -904,7 +1198,7 @@ private void createIncentiveRecordforHbncVisit(HbncVisit hbncVisit, Long benId, logger.info("RecordIncentive" + activityName); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), hbncVisit.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), hbncVisit.getCreatedDate(), benId,hbncVisit.getAshaId()); if (record == null) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); @@ -929,37 +1223,60 @@ record = new IncentiveActivityRecord(); } } - private void createIncentiveRecordforHbyncVisit(HbycChildVisit data, Long benId, IncentiveActivity immunizationActivity, String createdBy) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + private void updatePendingActivity(Integer userId, Long recordId, Long activityId, Long mIncentiveId) { + IncentivePendingActivity incentivePendingActivity = new IncentivePendingActivity(); + incentivePendingActivity.setActivityId(activityId); + incentivePendingActivity.setRecordId(recordId); + incentivePendingActivity.setUserId(userId); + incentivePendingActivity.setMincentiveId(mIncentiveId); + if (incentivePendingActivity != null) { + incentivePendingActivityRepository.save(incentivePendingActivity); + } - // Convert to LocalDate - LocalDate localDate = LocalDate.parse(data.getVisit_date(), formatter); + } - // Convert LocalDate to Timestamp (00:00:00 by default) - Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); + public HbncVisit updateHbncFromFileUpload(MultipartFile[] dischargeSncuImage, Long incentiveRecordId, Long id) throws JsonProcessingException { + HbncVisit existingHbncVisit = hbncVisitRepo.findById(id) + .orElseThrow(() -> new EntityNotFoundException("Meeting not found: " + id)); - if (record == null) { + // Images - only if provided + if (dischargeSncuImage != null && dischargeSncuImage.length > 0) { + List base64Images = Arrays.stream(dischargeSncuImage) + .filter(file -> file != null && !file.isEmpty()) + .map(this::convertToBase64) + .collect(Collectors.toList()); + existingHbncVisit.setDischarge_summary_upload(mapper.writeValueAsString(base64Images)); + } - record = new IncentiveActivityRecord(); - record.setActivityId(immunizationActivity.getId()); - record.setCreatedDate(visitDate); - record.setCreatedBy(createdBy); - record.setStartDate(visitDate); - record.setEndDate(visitDate); - record.setUpdatedDate(visitDate); - record.setUpdatedBy(createdBy); - record.setBenId(benId); - record.setAshaId(beneficiaryRepo.getUserIDByUserName(createdBy)); - record.setAmount(Long.valueOf(immunizationActivity.getRate())); + if (existingHbncVisit.getDischarge_summary_upload() != null) { + updateIncentive(incentiveRecordId); + + } + return hbncVisitRepo.save(existingHbncVisit); + } + + private void updateIncentive(Long id) { + + Optional optionalRecord = recordRepo.findById(id); + + if (optionalRecord.isPresent()) { + IncentiveActivityRecord record = optionalRecord.get(); + record.setIsEligible(true); recordRepo.save(record); } } - private void createIncentiveRecordforHbyncOrsDistribution(HbycChildVisit data, Long benId, IncentiveActivity immunizationActivity, String createdBy) { + private String convertToBase64(MultipartFile file) { + try { + return Base64.getEncoder().encodeToString(file.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Failed to convert image to Base64: " + file.getOriginalFilename(), e); + } + } + + private void createIncentiveRecordforHbyncVisit(HbycChildVisit data, Long benId, IncentiveActivity immunizationActivity, String createdBy) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); // Convert to LocalDate @@ -968,7 +1285,7 @@ private void createIncentiveRecordforHbyncOrsDistribution(HbycChildVisit data, L // Convert LocalDate to Timestamp (00:00:00 by default) Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId,data.getUserId()); if (record == null) { @@ -982,46 +1299,47 @@ record = new IncentiveActivityRecord(); record.setUpdatedDate(visitDate); record.setUpdatedBy(createdBy); record.setBenId(benId); - record.setAshaId(beneficiaryRepo.getUserIDByUserName(createdBy)); + record.setAshaId(data.getUserId()); record.setAmount(Long.valueOf(immunizationActivity.getRate())); recordRepo.save(record); } } - private void createIncentiveRecordforOrsDistribution(OrsDistribution data, Long benId, IncentiveActivity immunizationActivity, String createdBy,boolean isCH) { - try { - // Convert to LocalDate - Timestamp visitDate = Timestamp.valueOf(data.getVisitDate().atStartOfDay()); - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); - double packets = Double.parseDouble(data.getNumOrsPackets()); - double rate = immunizationActivity.getRate(); - - if (record == null) { - - record = new IncentiveActivityRecord(); - record.setActivityId(immunizationActivity.getId()); - record.setCreatedDate(visitDate); - record.setCreatedBy(createdBy); - record.setStartDate(visitDate); - record.setEndDate(visitDate); - record.setUpdatedDate(visitDate); - record.setUpdatedBy(createdBy); - record.setBenId(benId); - record.setAshaId(beneficiaryRepo.getUserIDByUserName(createdBy)); - if(isCH){ - record.setAmount((long) rate); - - }else { - record.setAmount((long) (rate * packets)); - - } - recordRepo.save(record); - } - }catch (Exception e){ - logger.error("Exp"+e.getMessage()); - - } + + private void createIncentiveRecordforOrsDistribution(OrsDistribution data, Long benId, IncentiveActivity immunizationActivity, String createdBy, boolean isCH) { + try { + // Convert to LocalDate + Timestamp visitDate = Timestamp.valueOf(data.getVisitDate().atStartOfDay()); + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId,data.getUserId()); + double packets = Double.parseDouble(data.getNumOrsPackets()); + double rate = immunizationActivity.getRate(); + + if (record == null) { + + record = new IncentiveActivityRecord(); + record.setActivityId(immunizationActivity.getId()); + record.setCreatedDate(visitDate); + record.setCreatedBy(createdBy); + record.setStartDate(visitDate); + record.setEndDate(visitDate); + record.setUpdatedDate(visitDate); + record.setUpdatedBy(createdBy); + record.setBenId(0L); + record.setAshaId(data.getUserId()); + if (isCH) { + record.setAmount((long) rate); + + } else { + record.setAmount((long) (rate * packets)); + + } + recordRepo.save(record); + } + } catch (Exception e) { + logger.error("Exp" + e.getMessage()); + + } } @@ -1030,7 +1348,7 @@ private void createIncentiveRecordforSamReferalToNrc(SamVisit data, Long benId, // Convert to LocalDate Timestamp visitDate = Timestamp.valueOf(data.getVisitDate().atStartOfDay()); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), visitDate, benId); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), visitDate, benId,data.getUserId()); if (record == null) { @@ -1043,12 +1361,14 @@ record = new IncentiveActivityRecord(); record.setUpdatedDate(visitDate); record.setUpdatedBy(createdBy); record.setBenId(benId); - record.setAshaId(beneficiaryRepo.getUserIDByUserName(createdBy)); + record.setAshaId(data.getUserId()); record.setAmount((long) incentiveActivity.getRate()); + record.setIsEligible(true); + record.setIsDefaultActivity(false); recordRepo.save(record); } - }catch (Exception e){ - logger.error("Exp"+e.getMessage()); + } catch (Exception e) { + logger.error("Exp" + e.getMessage()); } diff --git a/src/main/java/com/iemr/flw/service/impl/ChildServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildServiceImpl.java index 0ce841e83..32c6d76ac 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildServiceImpl.java @@ -2,18 +2,24 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.iemr.flw.domain.identity.RMNCHBeneficiaryDetailsRmnch; import com.iemr.flw.domain.iemr.ChildRegister; +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.domain.iemr.UserServiceRole; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.ChildRegisterDTO; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.ChildRegisterRepo; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.ChildService; +import com.iemr.flw.service.IncentiveLogicService; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -28,6 +34,12 @@ public class ChildServiceImpl implements ChildService { @Autowired private BeneficiaryRepo beneficiaryRepo; + @Autowired + private IncentiveLogicService incentiveLogicService; + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; + public String getByUserId(GetBenRequestHandler dto) { try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); @@ -38,6 +50,7 @@ public String getByUserId(GetBenRequestHandler dto) { // ChildRegisterDTO childDTO = modelMapper.map(childRegister, ChildRegisterDTO.class); // result.add(childDTO); // }); + List result = childRegisterList.stream() .map(childRegister -> modelMapper.map(childRegister, ChildRegisterDTO.class)) .collect(Collectors.toList()); @@ -68,6 +81,68 @@ public String save(List childRegisterDTOs) throws Exception { listToBeSaved.add(childRegister); }); childRepo.saveAll(listToBeSaved); + for (ChildRegister childRegister : listToBeSaved) { + processFirstChildIncentive(childRegister); + } + for (ChildRegister childRegister : listToBeSaved) { + processSecondChildGapIncentive(childRegister); + } return "no of child details saved: " + childRegisterDTOs.size(); } + + public void processFirstChildIncentive(ChildRegister childRegister) { + Long benId = childRegister.getBenId(); + logger.info("Child register {}"+childRegister.getBenId()); + + // First child validation + List childCount = childRepo.findByBenId(benId); + + + if(!childCount.isEmpty()){ + logger.info("Child register {}"+childCount.size()); + + if(childCount.size()==1){ + Integer userId = + userServiceRoleRepo.getUserIdByName(childRegister.getCreatedBy()); + + incentiveLogicService.incentiveForChildBirthGap( + benId, + childRegister.getCreatedDate(), + childRegister.getCreatedDate(), + userId + ); + } + } + + + + } + + private void processSecondChildGapIncentive(ChildRegister currentChild) { + + Long benId = currentChild.getBenId(); + + // Total children count + List childCount = childRepo.findByBenId(benId); + + // Applicable only for second child + + if(!childCount.isEmpty()){ + if(childCount.size()==2){ + Integer userId = + userServiceRoleRepo.getUserIdByName( + currentChild.getCreatedBy()); + + incentiveLogicService.incentiveForSecondChildGap( + benId, + currentChild.getCreatedDate(), + currentChild.getCreatedDate(), + userId + ); + } + } + + + + } } diff --git a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java index 95b0557b2..e22147afa 100644 --- a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java @@ -11,14 +11,17 @@ import com.iemr.flw.dto.iemr.EligibleCoupleDTO; import com.iemr.flw.dto.iemr.EligibleCoupleTrackingDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.CoupleService; +import com.iemr.flw.service.UserService; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @@ -27,6 +30,7 @@ import java.util.Arrays; import java.util.Base64; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Service @@ -46,6 +50,9 @@ public class CoupleServiceImpl implements CoupleService { @Autowired private UserServiceRoleRepo userRepo; + + @Autowired + private UserService userService; @Autowired private IncentiveRecordRepo recordRepo; @@ -54,82 +61,139 @@ public class CoupleServiceImpl implements CoupleService { private BeneficiaryRepo beneficiaryRepo; private final Logger logger = LoggerFactory.getLogger(CoupleServiceImpl.class); + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + @Override - public String registerEligibleCouple(List eligibleCoupleDTOs, MultipartFile kitPhoto1, MultipartFile kitPhoto2) { + @Transactional + public String registerEligibleCouple(List eligibleCoupleDTOs, + MultipartFile kitPhoto1, + MultipartFile kitPhoto2) { try { + List ecrList = new ArrayList<>(); - List recordList = new ArrayList<>(); - eligibleCoupleDTOs.forEach(it -> { - EligibleCoupleRegister existingECR = -// eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenIdAndCreatedDate(it.getBenId(), it.getCreatedDate()); - eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(it.getBenId()); - if (kitPhoto1 != null) { - String kitPhoto1base64Image = null; - try { - kitPhoto1base64Image = Base64.getEncoder().encodeToString(kitPhoto1.getBytes()); - } catch (IOException e) { - throw new RuntimeException(e); + if(!eligibleCoupleDTOs.isEmpty()){ + for (EligibleCoupleDTO it : eligibleCoupleDTOs) { + Integer userId = userRepo.getUserIdByName(it.getCreatedBy()); + Integer stateId = userService.getUserDetail(userId).getStateId(); + EligibleCoupleRegister existingECR = + eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(it.getBenId()); + + boolean isNew = false; + + if (existingECR == null) { + existingECR = new EligibleCoupleRegister(); + isNew = true; } - existingECR.setKitPhoto1(String.valueOf(kitPhoto1base64Image)); - } + Long id = existingECR.getId(); + modelMapper.map(it, existingECR); - if (kitPhoto2 != null) { - String kitPhoto2base64Image = null; - try { - kitPhoto2base64Image = Base64.getEncoder().encodeToString(kitPhoto2.getBytes()); - } catch (IOException e) { - throw new RuntimeException(e); - } - existingECR.setKitPhoto2(String.valueOf(kitPhoto2base64Image)); + existingECR.setId(id); - } + // Photo 1 + if (kitPhoto1 != null && !kitPhoto1.isEmpty()) { + existingECR.setKitPhoto1( + Base64.getEncoder().encodeToString(kitPhoto1.getBytes())); + } - if (existingECR != null && null != existingECR.getNumLiveChildren()) { - if (existingECR.getNumLiveChildren() == 0 && it.getNumLiveChildren() >= 1 && it.getMarriageFirstChildGap() != null && it.getMarriageFirstChildGap() >= 2) { - IncentiveActivity activity1 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_DELAY_2Y", GroupName.FAMILY_PLANNING.getDisplayName()); - createIncentiveRecord(recordList, it, activity1); - } else if (existingECR.getNumLiveChildren() == 1 && it.getNumLiveChildren() >= 2 && it.getFirstAndSecondChildGap() != null && it.getFirstAndSecondChildGap() == 3) { - IncentiveActivity activity2 = - incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", GroupName.FAMILY_PLANNING.getDisplayName()); - createIncentiveRecord(recordList, it, activity2); + // Photo 2 + if (kitPhoto2 != null && !kitPhoto2.isEmpty()) { + existingECR.setKitPhoto2( + Base64.getEncoder().encodeToString(kitPhoto2.getBytes())); } - Long id = existingECR.getId(); - modelMapper.map(it, existingECR); - existingECR.setId(id); - } else { - existingECR = new EligibleCoupleRegister(); - modelMapper.map(it, existingECR); - existingECR.setId(null); - } - if (existingECR.getIsKitHandedOver() && (!existingECR.getKitPhoto1().isEmpty() || !existingECR.getKitPhoto2().isEmpty())) { - IncentiveActivity handoverKitActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_NP_KIT", GroupName.FAMILY_PLANNING.getDisplayName()); - if (handoverKitActivityAM != null) { - createIncentiveRecord(recordList, it, handoverKitActivityAM); + // Incentive only for new registration + if (isNew) { + + if (it.getMarriageFirstChildGap() != null + && it.getMarriageFirstChildGap() >= 2) { + + IncentiveActivity activity = null; + + if (stateId.equals(StateCode.AM.getStateCode())) { + activity = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.FAMILY_PLANNING.getDisplayName()); + + } else if (stateId.equals(StateCode.CG.getStateCode())) { + activity = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.ACTIVITY.getDisplayName()); + } + + if (activity != null) { + createIncentiveRecord(existingECR, activity); + } + } + + if (it.getFirstAndSecondChildGap() != null + && it.getFirstAndSecondChildGap() >= 3) { + + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.FAMILY_PLANNING.getDisplayName()); + + createIncentiveRecord(existingECR, activity); + + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecord(existingECR, activity); + } + } } + // Kit Incentive + if (Boolean.TRUE.equals(existingECR.getIsKitHandedOver()) + && ((existingECR.getKitPhoto1() != null && !existingECR.getKitPhoto1().isEmpty()) + || (existingECR.getKitPhoto2() != null && !existingECR.getKitPhoto2().isEmpty()))) { + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_NP_KIT", + GroupName.FAMILY_PLANNING.getDisplayName()); + + if (activity != null) { + createIncentiveRecord(existingECR, activity); + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_NP_KIT", + GroupName.ACTIVITY.getDisplayName()); + + if (activity != null) { + createIncentiveRecord(existingECR, activity); + } + } - IncentiveActivity handoverKitActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_NP_KIT", GroupName.ACTIVITY.getDisplayName()); - if (handoverKitActivityCH != null) { - createIncentiveRecord(recordList, it, handoverKitActivityCH); } + + ecrList.add(existingECR); } - ecrList.add(existingECR); - }); - eligibleCoupleRegisterRepo.saveAll(ecrList); - recordRepo.saveAll(recordList); - return "no of ecr details saved: " + ecrList.size(); + + eligibleCoupleRegisterRepo.saveAll(ecrList); + + } + + + return "No of ECR details saved: " + ecrList.size(); + } catch (Exception e) { - return "error while saving ecr details: " + e.getMessage(); + logger.error("Error while saving Eligible Couple Registration", e); + return "Error while saving ECR details: " + e.getMessage(); } } @@ -137,46 +201,141 @@ public String registerEligibleCouple(List eligibleCoupleDTOs, public String registerEligibleCouple(List eligibleCoupleDTOs) { try { List ecrList = new ArrayList<>(); - List recordList = new ArrayList<>(); eligibleCoupleDTOs.forEach(it -> { EligibleCoupleRegister existingECR = -// eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenIdAndCreatedDate(it.getBenId(), it.getCreatedDate()); eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(it.getBenId()); - - if (existingECR != null && null != existingECR.getNumLiveChildren()) { - if (it.getNumLiveChildren() >= 1 && it.getMarriageFirstChildGap() != null && it.getMarriageFirstChildGap() >= 2) { - IncentiveActivity activity1 = - incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", GroupName.FAMILY_PLANNING.getDisplayName()) - ; - - IncentiveActivity activityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecord(recordList, it, activity1); - createIncentiveRecord(recordList, it, activityCH); - } else if (it.getNumLiveChildren() >= 2 && it.getMarriageFirstChildGap() != null && it.getMarriageFirstChildGap() >= 3) { - IncentiveActivity activity2 = - incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", GroupName.FAMILY_PLANNING.getDisplayName()); - - IncentiveActivity activityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecord(recordList, it, activity2); - createIncentiveRecord(recordList, it, activityCH); - } + if(existingECR!=null){ Long id = existingECR.getId(); modelMapper.map(it, existingECR); existingECR.setId(id); - } else { + }else { existingECR = new EligibleCoupleRegister(); modelMapper.map(it, existingECR); existingECR.setId(null); } + ecrList.add(existingECR); + + }); + + eligibleCoupleRegisterRepo.saveAll(ecrList); + if(!ecrList.isEmpty()){ + Integer userId = userRepo.getUserIdByName(ecrList.get(0).getCreatedBy()); + Integer stateId = userService.getUserDetail(userId).getStateId(); + checkIncentiveForChildGap(stateId,ecrList.get(0).getCreatedBy(),ecrList); + + } + return "no of ecr details saved: " + ecrList.size(); + } catch (Exception e) { + return "error while saving ecr details: " + e.getMessage(); + } + } + + + private void checkIncentiveForChildGap(Integer stateId, String userName,List eligibleCoupleRegisters) { + + logger.info("Checking Child Gap Incentive for user: {}, stateId: {}", userName, stateId); + + + logger.info("Eligible Couple Records Found: {}", eligibleCoupleRegisters.size()); + + if (!eligibleCoupleRegisters.isEmpty()) { + + eligibleCoupleRegisters.forEach(eligibleCoupleRegister -> { + + logger.info( + "Processing EligibleCoupleRegister -> BenId: {}, NumChildren: {}, MarriageFirstChildGap: {}, FirstAndSecondChildGap: {}", + eligibleCoupleRegister.getBenId(), + eligibleCoupleRegister.getNumChildren(), + eligibleCoupleRegister.getMarriageFirstChildGap(), + eligibleCoupleRegister.getFirstAndSecondChildGap()); + + // Marriage -> First Child Gap + if(eligibleCoupleRegister.getFirstAndSecondChildGap()!=null){ + if (eligibleCoupleRegister.getFirstAndSecondChildGap()>=2 ) { + + logger.info("Marriage -> First Child Gap condition matched."); + + if (stateId.equals(StateCode.AM.getStateCode())) { + + logger.info("Fetching incentive for Assam."); + + IncentiveActivity activity1 = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.FAMILY_PLANNING.getDisplayName()); + + logger.info("Incentive Activity: {}", activity1); + + createIncentiveRecord(eligibleCoupleRegister, activity1); - if (existingECR.getIsKitHandedOver()) { + logger.info("Marriage -> First Child Gap incentive created."); + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + + logger.info("Fetching incentive for Chhattisgarh."); + + IncentiveActivity activityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.ACTIVITY.getDisplayName()); + + logger.info("Incentive Activity: {}", activityCH); + + createIncentiveRecord(eligibleCoupleRegister, activityCH); + + logger.info("Marriage -> First Child Gap incentive created."); + } + } + } + + + // First -> Second Child Gap + if(eligibleCoupleRegister.getMarriageFirstChildGap()!=null){ + if (eligibleCoupleRegister.getMarriageFirstChildGap()>=3) { + + logger.info("1st -> 2nd Child Gap condition matched."); + + if (stateId.equals(StateCode.AM.getStateCode())) { + + logger.info("Fetching incentive for Assam."); + + IncentiveActivity activity2 = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.FAMILY_PLANNING.getDisplayName()); + + logger.info("Incentive Activity: {}", activity2); + + createIncentiveRecord(eligibleCoupleRegister, activity2); + + logger.info("1st -> 2nd Child Gap incentive created."); + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + + logger.info("Fetching incentive for Chhattisgarh."); + + IncentiveActivity activityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.ACTIVITY.getDisplayName()); + + logger.info("Incentive Activity: {}", activityCH); + + createIncentiveRecord(eligibleCoupleRegister, activityCH); + + logger.info("1st -> 2nd Child Gap incentive created."); + } + } + } + + if (eligibleCoupleRegister.getIsKitHandedOver()!=null && eligibleCoupleRegister.getIsKitHandedOver()) { IncentiveActivity handoverKitActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("FP_NP_KIT", GroupName.FAMILY_PLANNING.getDisplayName()); if (handoverKitActivityAM != null) { - createIncentiveRecord(recordList, it, handoverKitActivityAM); + createIncentiveRecord(eligibleCoupleRegister, handoverKitActivityAM); } @@ -184,41 +343,54 @@ public String registerEligibleCouple(List eligibleCoupleDTOs) IncentiveActivity handoverKitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("FP_NP_KIT", GroupName.ACTIVITY.getDisplayName()); if (handoverKitActivityCH != null) { - createIncentiveRecord(recordList, it, handoverKitActivityCH); + createIncentiveRecord(eligibleCoupleRegister, handoverKitActivityCH); } } - ecrList.add(existingECR); + + + + }); - eligibleCoupleRegisterRepo.saveAll(ecrList); - recordRepo.saveAll(recordList); - return "no of ecr details saved: " + ecrList.size(); - } catch (Exception e) { - return "error while saving ecr details: " + e.getMessage(); + + } else { + logger.info("No Eligible Couple Register records found for user: {}", userName); } + + logger.info("Completed Child Gap Incentive check for user: {}", userName); } - private void createIncentiveRecord(List recordList, EligibleCoupleDTO eligibleCoupleDTO, IncentiveActivity activity) { - if (activity != null) { - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(activity.getId(), eligibleCoupleDTO.getCreatedDate(), eligibleCoupleDTO.getBenId()); - Integer userId = userRepo.getUserIdByName(eligibleCoupleDTO.getCreatedBy()); - if (record == null) { - record = new IncentiveActivityRecord(); - record.setActivityId(activity.getId()); - record.setCreatedDate(eligibleCoupleDTO.getCreatedDate()); - record.setCreatedBy(eligibleCoupleDTO.getCreatedBy()); - record.setStartDate(eligibleCoupleDTO.getCreatedDate()); - record.setEndDate(eligibleCoupleDTO.getCreatedDate()); - record.setUpdatedDate(eligibleCoupleDTO.getCreatedDate()); - record.setUpdatedBy(eligibleCoupleDTO.getCreatedBy()); - record.setBenId(eligibleCoupleDTO.getBenId()); - record.setAshaId(userId); - record.setAmount(Long.valueOf(activity.getRate())); - recordList.add(record); + private void createIncentiveRecord(EligibleCoupleRegister eligibleCoupleDTO, IncentiveActivity activity) { + String lockKey = activity.getId() + "_" + eligibleCoupleDTO.getBenId() + "_" + eligibleCoupleDTO.getCreatedDate(); + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + synchronized (lock){ + if (activity != null) { + Integer userId = userRepo.getUserIdByName(eligibleCoupleDTO.getCreatedBy()); + + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), eligibleCoupleDTO.getCreatedDate(), eligibleCoupleDTO.getBenId(),userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(eligibleCoupleDTO.getCreatedDate()); + record.setCreatedBy(eligibleCoupleDTO.getCreatedBy()); + record.setStartDate(eligibleCoupleDTO.getCreatedDate()); + record.setEndDate(eligibleCoupleDTO.getCreatedDate()); + record.setUpdatedDate(eligibleCoupleDTO.getCreatedDate()); + record.setUpdatedBy(eligibleCoupleDTO.getCreatedBy()); + record.setBenId(eligibleCoupleDTO.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(activity.getRate())); + recordRepo.save(record); + } } } + lockMap.remove(lockKey, lock); + + + } @Override @@ -240,7 +412,7 @@ public String registerEligibleCoupleTracking(List eli ect.setId(null); } ectList.add(ect); - checkAndAddAntaraIncentive(recordList, ect); + checkAndAddAntaraIncentive(ect); }); eligibleCoupleTrackingRepo.saveAll(ectList); recordRepo.saveAll(recordList); @@ -250,135 +422,170 @@ public String registerEligibleCoupleTracking(List eli } } - private void checkAndAddAntaraIncentive(List recordList, EligibleCoupleTracking ect) { + private void checkAndAddAntaraIncentive(EligibleCoupleTracking ect) { Integer userId = userRepo.getUserIdByName(ect.getCreatedBy()); logger.info("Antra" + ect.getMethodOfContraception()); logger.info("Antra" + ect.getAntraDose()); + Integer stateId = userService.getUserDetail(userId).getStateId(); if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().contains("ANTRA Injection")) { - // for CG incentive - IncentiveActivity antaraActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", GroupName.ACTIVITY.getDisplayName()); - if (antaraActivityCH != null) { - String dose = ect.getAntraDose(); + if(stateId.equals(StateCode.CG.getStateCode())){ + // for CG incentive + IncentiveActivity antaraActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", GroupName.ACTIVITY.getDisplayName()); + if (antaraActivityCH != null) { + String dose = ect.getAntraDose(); - List validDoses = Arrays.asList("Dose-1", "Dose-2", "Dose-3", "Dose-4"); + List validDoses = Arrays.asList("Dose-1", "Dose-2", "Dose-3", "Dose-4"); - boolean isDose = validDoses.stream().anyMatch(dose::contains); + boolean isDose = validDoses.stream().anyMatch(dose::contains); - if (isDose) { - addIncenticeRecord(recordList, ect, userId, antaraActivityCH); + if (isDose) { + addIncenticeRecord(ect, userId, antaraActivityCH); + } } } - if (ect.getAntraDose().contains("Dose-1")) { - IncentiveActivity antaraActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", "FAMILY PLANNING"); - if (antaraActivity != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity); - } - } else if (ect.getAntraDose().contains("Dose-2")) { - IncentiveActivity antaraActivity2 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA2", "FAMILY PLANNING"); - if (antaraActivity2 != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity2); - } - } else if (ect.getAntraDose().contains("Dose-3")) { - IncentiveActivity antaraActivity3 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA3", "FAMILY PLANNING"); - if (antaraActivity3 != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity3); - } - } else if (ect.getAntraDose().contains("Dose-4")) { - IncentiveActivity antaraActivity4 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA4", "FAMILY PLANNING"); - if (antaraActivity4 != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity4); - } + if(stateId.equals(StateCode.AM.getStateCode())){ + if (ect.getAntraDose().contains("Dose-1")) { + IncentiveActivity antaraActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", "FAMILY PLANNING"); + if (antaraActivity != null) { + addIncenticeRecord(ect, userId, antaraActivity); + } + } else if (ect.getAntraDose().contains("Dose-2")) { + IncentiveActivity antaraActivity2 = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA2", "FAMILY PLANNING"); + if (antaraActivity2 != null) { + addIncenticeRecord(ect, userId, antaraActivity2); + } + } else if (ect.getAntraDose().contains("Dose-3")) { + IncentiveActivity antaraActivity3 = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA3", "FAMILY PLANNING"); + if (antaraActivity3 != null) { + addIncenticeRecord(ect, userId, antaraActivity3); + } + } else if (ect.getAntraDose().contains("Dose-4")) { + IncentiveActivity antaraActivity4 = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA4", "FAMILY PLANNING"); + if (antaraActivity4 != null) { + addIncenticeRecord(ect, userId, antaraActivity4); + } - } else if (ect.getAntraDose().contains("Dose-5")) { - IncentiveActivity antaraActivity4 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA5", GroupName.FAMILY_PLANNING.getDisplayName()); + }else if (ect.getAntraDose().contains("Dose-5")) { + IncentiveActivity antaraActivity4 = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA5", GroupName.FAMILY_PLANNING.getDisplayName()); + + if (antaraActivity4 != null) { + addIncenticeRecord(ect, userId, antaraActivity4); + } + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ IncentiveActivity antaraActivity4CH = incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", GroupName.ACTIVITY.getDisplayName()); if (antaraActivity4CH != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity4CH); - } - - if (antaraActivity4 != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity4); + addIncenticeRecord(ect, userId, antaraActivity4CH); } } + + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("MALE STERILIZATION")) { - - IncentiveActivity maleSterilizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", "FAMILY PLANNING"); - - IncentiveActivity maleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); - if (maleSterilizationActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, maleSterilizationActivityAM); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity maleSterilizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", "FAMILY PLANNING"); + + if (maleSterilizationActivityAM != null) { + addIncenticeRecord(ect, userId, maleSterilizationActivityAM); + } + } - - if (maleSterilizationActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, maleSterilizationActivityCH); + if(stateId.equals(StateCode.CG.getStateCode())){ + + IncentiveActivity maleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); + + + if (maleSterilizationActivityCH != null) { + addIncenticeRecord(ect, userId, maleSterilizationActivityCH); + } } + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("FEMALE STERILIZATION")) { + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity femaleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity femaleSterilizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); - - IncentiveActivity femaleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - if (femaleSterilizationActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, femaleSterilizationActivityAM); + if (femaleSterilizationActivityCH != null) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityCH); + } } + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity femaleSterilizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); + if (femaleSterilizationActivityAM != null) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityAM); + } - if (femaleSterilizationActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, femaleSterilizationActivityCH); } - } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("MiniLap")) { - IncentiveActivity miniLapActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MINILAP", "FAMILY PLANNING"); - if (miniLapActivity != null) { - addIncenticeRecord(recordList, ect, userId, miniLapActivity); + + + + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("MiniLap")) { + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity miniLapActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MINILAP", "FAMILY PLANNING"); + if (miniLapActivity != null) { + addIncenticeRecord(ect, userId, miniLapActivity); + } } + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("Condom")) { - - IncentiveActivity comdomActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", "FAMILY PLANNING"); - if (comdomActivity != null) { - addIncenticeRecord(recordList, ect, userId, comdomActivity); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity comdomActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", "FAMILY PLANNING"); + if (comdomActivity != null) { + addIncenticeRecord(ect, userId, comdomActivity); + } } + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("Copper T (IUCD)")) { - - IncentiveActivity copperTActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", "FAMILY PLANNING"); - if (copperTActivity != null) { - addIncenticeRecord(recordList, ect, userId, copperTActivity); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity copperTActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", "FAMILY PLANNING"); + if (copperTActivity != null) { + addIncenticeRecord(ect, userId, copperTActivity); + } } + } if (ect.getMethodOfContraception() != null && (ect.getMethodOfContraception().contains("POST PARTUM STERILIZATION (PPS WITHIN 7 DAYS OF DELIVERY)") || ect.getMethodOfContraception().contains("MiniLap") || ect.getMethodOfContraception().contains("MALE STERILIZATION") || ect.getMethodOfContraception().contains("FEMALE STERILIZATION"))) { - IncentiveActivity limitiing2ChildActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_LIMIT_2CHILD", GroupName.FAMILY_PLANNING.getDisplayName()); - - IncentiveActivity limitiing2ChildActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_LIMIT_2CHILD", GroupName.ACTIVITY.getDisplayName()); - if (limitiing2ChildActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, limitiing2ChildActivityAM); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity limitiing2ChildActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_LIMIT_2CHILD", GroupName.FAMILY_PLANNING.getDisplayName()); + if (limitiing2ChildActivityAM != null) { + addIncenticeRecord(ect, userId, limitiing2ChildActivityAM); + } } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity limitiing2ChildActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_LIMIT_2CHILD", GroupName.ACTIVITY.getDisplayName()); + - if (limitiing2ChildActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, limitiing2ChildActivityCH); + if (limitiing2ChildActivityCH != null) { + addIncenticeRecord(ect, userId, limitiing2ChildActivityCH); + } } + + } } - private void addIncenticeRecord(List recordList, EligibleCoupleTracking ect, Integer userId, IncentiveActivity antaraActivity) { + private void addIncenticeRecord(EligibleCoupleTracking ect, Integer userId, IncentiveActivity antaraActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getCreatedDate(), ect.getBenId()); + .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getVisitDate(), ect.getBenId(),userId); // get bene details if (record == null) { @@ -393,7 +600,7 @@ record = new IncentiveActivityRecord(); record.setBenId(ect.getBenId()); record.setAshaId(userId); record.setAmount(Long.valueOf(antaraActivity.getRate())); - recordList.add(record); + recordRepo.save(record); } } @@ -409,6 +616,7 @@ public String getEligibleCoupleRegRecords(GetBenRequestHandler dto) { Gson gson = new GsonBuilder() .serializeNulls() .setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return gson.toJson(list); } catch (Exception e) { logger.error(e.getMessage()); @@ -418,6 +626,7 @@ public String getEligibleCoupleRegRecords(GetBenRequestHandler dto) { @Override public List getEligibleCoupleTracking(GetBenRequestHandler dto) { + List recordList = new ArrayList<>(); try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); @@ -425,9 +634,12 @@ public List getEligibleCoupleTracking(GetBenRequestHa List eligibleCoupleTrackingList = eligibleCoupleTrackingRepo.getECTrackRecords(user, dto.getFromDate(), dto.getToDate()); + recordRepo.saveAll(recordList); + return eligibleCoupleTrackingList.stream() .map(ect -> mapper.convertValue(ect, EligibleCoupleTrackingDTO.class)) .collect(Collectors.toList()); + } catch (Exception e) { logger.error(e.getMessage()); } diff --git a/src/main/java/com/iemr/flw/service/impl/CrashLogServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CrashLogServiceImpl.java index da2fbaa02..4c85ae66c 100644 --- a/src/main/java/com/iemr/flw/service/impl/CrashLogServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CrashLogServiceImpl.java @@ -24,7 +24,7 @@ public class CrashLogServiceImpl implements CrashLogService { private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - @Value("${crash.logs.base.path}") + // @Value("${crash.logs.base.path}") private String crashLogsBasePath; @Override diff --git a/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java index 82cee5d06..b7eee7dd0 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java @@ -7,15 +7,19 @@ import com.iemr.flw.dto.iemr.CdrDTO; import com.iemr.flw.dto.iemr.MdsrDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.DeathReportsService; import org.modelmapper.ModelMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; @Service @@ -43,16 +47,20 @@ public class DeathReportsServiceImpl implements DeathReportsService { @Autowired private IncentiveRecordRepo recordRepo; + @Autowired + private UpdateIncentivePendindDocService pendindDocService; + + private final Logger logger = LoggerFactory.getLogger(DeathReportsServiceImpl.class); @Override public String registerCDR(List cdrDTOs) { try { List cdrList = new ArrayList<>(); - cdrDTOs.forEach(it ->{ + cdrDTOs.forEach(it -> { CDR existingCDR = cdrRepo.findCDRByBenId(it.getBenId()); - if(existingCDR != null) { + if (existingCDR != null) { Long id = existingCDR.getId(); modelMapper.map(it, existingCDR); existingCDR.setId(id); @@ -73,15 +81,47 @@ public String registerCDR(List cdrDTOs) { } } + public String updateCDRUploadFiles(CdrDTO cdrDTOs, Long incentiveActivityId) { + try { + Optional cdrOptional = cdrRepo.findById(cdrDTOs.getId()); + CDR cdr = new CDR(); + if (cdrOptional.isPresent()) { + cdr = cdrOptional.get(); + if (cdrDTOs.getCdrImage() != null && !cdrDTOs.getCdrImage().isEmpty()) { + cdr.setCdrImage(cdrDTOs.getCdrImage()); + } + + if (cdrDTOs.getCdrImage2() != null && !cdrDTOs.getCdrImage2().isEmpty()) { + cdr.setCdrImage2(cdrDTOs.getCdrImage2()); + } + + if (cdrDTOs.getDeathCertImage1() != null && !cdrDTOs.getDeathCertImage1().isEmpty()) { + cdr.setDeathCertImage1(cdrDTOs.getDeathCertImage1()); + } + + if (cdrDTOs.getDeathCertImage2() != null && !cdrDTOs.getDeathCertImage2().isEmpty()) { + cdr.setDeathCertImage2(cdrDTOs.getDeathCertImage2()); + } + } + cdrRepo.save(cdr); + + pendindDocService.updateIncentive(incentiveActivityId); + + return "no of cdr details update: "; + } catch (Exception e) { + return "error while saving cdr details: " + e.getMessage(); + } + } + @Override public String registerMDSR(List mdsrDTOs) { try { List mdsrList = new ArrayList<>(); - mdsrDTOs.forEach(it ->{ + mdsrDTOs.forEach(it -> { MDSR mdsr = mdsrRepo.findMDSRByBenId(it.getBenId()); - if(mdsr != null) { + if (mdsr != null) { Long id = mdsr.getId(); modelMapper.map(it, mdsr); mdsr.setId(id); @@ -101,16 +141,56 @@ public String registerMDSR(List mdsrDTOs) { } } + public String updateMDSR(MdsrDTO mdsrDTO, Long incentiveActivityId) { + try { + + Optional mdsrOptional = mdsrRepo.findById(mdsrDTO.getId()); + MDSR mdsr = new MDSR(); + + if (mdsrOptional.isPresent()) { + + mdsr = mdsrOptional.get(); + + if (mdsrDTO.getMdsr1File() != null && !mdsrDTO.getMdsr1File().isEmpty()) { + mdsr.setMdsr1File(mdsrDTO.getMdsr1File()); + } + + if (mdsrDTO.getMdsr2File() != null && !mdsrDTO.getMdsr2File().isEmpty()) { + mdsr.setMdsr2File(mdsrDTO.getMdsr2File()); + } + + if (mdsrDTO.getMdsrDeathCertFile() != null && !mdsrDTO.getMdsrDeathCertFile().isEmpty()) { + mdsr.setMdsrDeathCertFile(mdsrDTO.getMdsrDeathCertFile()); + } + + } else { + return "MDSR record not found with id: " + mdsrDTO.getId(); + } + + mdsrRepo.save(mdsr); + + // incentive update + pendindDocService.updateIncentive(incentiveActivityId); + + return "MDSR updated successfully for id: " + mdsrDTO.getId(); + + } catch (Exception e) { + return "error while updating mdsr details: " + e.getMessage(); + } + } + @Override public List getCdrRecords(GetBenRequestHandler dto) { - try{ - String user = beneficiaryRepo.getUserName(dto.getAshaId()); + try { + String user = userRepo.getUserNamedByUserId(dto.getAshaId()); List cdrlist = - cdrRepo.getAllCdrByBenId(user, dto.getFromDate(), dto.getToDate()); + cdrRepo.findByCreatedBy(user); return cdrlist.stream() .map(cdr -> mapper.convertValue(cdr, CdrDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { + logger.error("MDSR Exception:" + e.getMessage()); + // log } return null; @@ -120,47 +200,74 @@ public List getCdrRecords(GetBenRequestHandler dto) { public List getMdsrRecords(GetBenRequestHandler dto) { try { - String user = beneficiaryRepo.getUserName(dto.getAshaId()); + String user = userRepo.getUserNamedByUserId(dto.getAshaId()); List mdsrList = - mdsrRepo.getAllMdsrByAshaId(user, dto.getFromDate(), dto.getToDate()); + mdsrRepo.findByCreatedBy(user); return mdsrList.stream() .map(mdsr -> mapper.convertValue(mdsr, MdsrDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { + logger.error("MDSR Exception:" + e.getMessage()); + // log } return null; } private void checkAndAddIncentives(List cdrList) { + if(!cdrList.isEmpty()){ + Integer userId = userRepo.getUserIdByName(cdrList.get(0).getCreatedBy()); + cdrList.forEach(cdr -> { + IncentiveActivity immunizationActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); + createIncentiveRecord(cdr, cdr.getBenId(), userId, immunizationActivity); + if(immunizationActivity!=null){ + createIncentiveRecord(cdr,cdr.getBenId(),userId,immunizationActivity); + + } + }); + + } + - cdrList.forEach( cdr -> { - Integer userId = userRepo.getUserIdByName(cdr.getCreatedBy()); - IncentiveActivity immunizationActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); - createIncentiveRecord(cdr,cdr.getBenId(),userId,immunizationActivity); - }); } private void checkAndAddIncentivesMdsr(List mdsrList) { - - mdsrList.forEach( mdsr -> { + mdsrList.forEach(mdsr -> { Integer userId = userRepo.getUserIdByName(mdsr.getCreatedBy()); - IncentiveActivity immunizationActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("MATERNAL_DEATH_REPORT", GroupName.MATERNAL_HEALTH.getDisplayName()); + Integer stateId = userRepo.getUserRole(userId).get(0).getStateId(); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity immunizationActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("MATERNAL_DEATH_REPORT", GroupName.MATERNAL_HEALTH.getDisplayName()); + + if(immunizationActivity!=null){ + createIncentiveRecord(mdsr,mdsr.getBenId(),userId,immunizationActivity); + + } + + + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity cgImmunizationActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("MATERNAL_DEATH_REPORT", GroupName.ACTIVITY.getDisplayName()); + + if(cgImmunizationActivity!=null){ + createIncentiveRecord(mdsr,mdsr.getBenId(),userId,cgImmunizationActivity); + + } + } + - createIncentiveRecord(mdsr,mdsr.getBenId(),userId,immunizationActivity); }); } - private void createIncentiveRecord(CDR cdr, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), cdr.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), cdr.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(immunizationActivity.getId()); @@ -173,13 +280,16 @@ record = new IncentiveActivityRecord(); record.setBenId(benId); record.setAshaId(userId); record.setAmount(Long.valueOf(immunizationActivity.getRate())); + record.setIsEligible(true); recordRepo.save(record); + + } } private void createIncentiveRecord(MDSR mdsr, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), mdsr.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), mdsr.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(immunizationActivity.getId()); @@ -192,14 +302,29 @@ record = new IncentiveActivityRecord(); record.setBenId(benId); record.setAshaId(userId); record.setAmount(Long.valueOf(immunizationActivity.getRate())); - recordRepo.save(record); - } - } + if (userRepo.getUserRole(userId).get(0).getStateId() == StateCode.AM.getStateCode()) { + if (mdsr.getMdsrDeathCertFile() != null && mdsr.getMdsr1File() != null && mdsr.getMdsr2File() != null) { + record.setIsEligible(true); + recordRepo.save(record); + + } else { + record.setIsEligible(false); + IncentiveActivityRecord incentiveActivityRecord = recordRepo.save(record); + if (incentiveActivityRecord == null) { + recordRepo.save(record); + pendindDocService.updatePendingActivity(userId, mdsr.getId(), record.getId(), immunizationActivity.getId()); + } + } + } else { + recordRepo.save(record); + } + } + } } diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index 0e329f4bf..3170deba0 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -11,6 +11,7 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.DeliveryOutcomeDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.identity.HouseHoldRepo; import com.iemr.flw.repo.iemr.DeliveryOutcomeRepo; @@ -18,6 +19,7 @@ import com.iemr.flw.repo.iemr.IncentivesRepo; import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.DeliveryOutcomeService; +import com.iemr.flw.service.UserService; import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.Validate; import org.modelmapper.ModelMapper; @@ -27,6 +29,10 @@ import org.springframework.stereotype.Service; import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -51,6 +57,9 @@ public class DeliveryOutcomeServiceImpl implements DeliveryOutcomeService { @Autowired private UserServiceRoleRepo userRepo; + @Autowired + private UserService userService; + @Autowired private IncentiveRecordRepo recordRepo; @@ -108,98 +117,185 @@ public String registerDeliveryOutcome(List deliveryOutcomeDT @Override public List getDeliveryOutcome(GetBenRequestHandler dto) { try { - String user = beneficiaryRepo.getUserName(dto.getAshaId()); - List deliveryOutcomeList = deliveryOutcomeRepo.getDeliveryOutcomeByAshaId(user, dto.getFromDate(), dto.getToDate()); + String user = userRepo.getUserNamedByUserId(dto.getAshaId()); + List deliveryOutcomeList = deliveryOutcomeRepo.getDeliveryOutcomeByAshaId(user,dto.getFromDate(),dto.getToDate()); + logger.info("DeliveryOutcome Response{}",deliveryOutcomeList); return deliveryOutcomeList.stream() .map(deliveryOutcome -> mapper.convertValue(deliveryOutcome, DeliveryOutcomeDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { - logger.error(e.getMessage()); + logger.error("DeliveryOutcome Exception:"+e.getMessage()); } return null; } public void checkAndAddJsyIncentive(List delOutList) { + if(!delOutList.isEmpty()){ + Integer userID = userRepo.getUserIdByName(delOutList.get(0).getCreatedBy()); + Integer stateId = userService.getUserDetail(userID).getStateId(); + delOutList.forEach(deliveryOutcome -> { + + IncentiveActivity institutionalDeliveryActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MH_MOTIVATE_INST_DEL", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity institutionalDeliveryActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("INST_DELIVERY_ESCORT", GroupName.ACTIVITY.getDisplayName()); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + + if (placeOfDelivery != null && + (!placeOfDelivery.equalsIgnoreCase("home") || + !placeOfDelivery.equalsIgnoreCase("in transit") || + !placeOfDelivery.equalsIgnoreCase("other private hospital"))) { + + // Institutional delivery (eligible case) + if (institutionalDeliveryActivityAM != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityAM); + } - delOutList.forEach(deliveryOutcome -> { - - IncentiveActivity institutionalDeliveryActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MH_MOTIVATE_INST_DEL", GroupName.MATERNAL_HEALTH.getDisplayName()); - IncentiveActivity institutionalDeliveryActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("INST_DELIVERY_ESCORT", GroupName.ACTIVITY.getDisplayName()); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); - - if (placeOfDelivery != null && - (!placeOfDelivery.equalsIgnoreCase("home") || - !placeOfDelivery.equalsIgnoreCase("in transit") || - !placeOfDelivery.equalsIgnoreCase("other private hospital"))) { - - // Institutional delivery (eligible case) - if (institutionalDeliveryActivityAM != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityAM); + if (institutionalDeliveryActivityCH != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityCH); + } } + } - if (institutionalDeliveryActivityCH != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityCH); + if (deliveryOutcome.getIsJSYBenificiary()) { + IncentiveActivity incentiveActivityInstJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + + + logger.info("delOutList" + gson.toJson(deliveryOutcome)); + IncentiveActivity incentiveActivityJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY1 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 1) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); + } + } } - } - } - if (deliveryOutcome.getIsJSYBenificiary()) { - IncentiveActivity incentiveActivityInstJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY2 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 2) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY2); + if (deliveryOutcome.getPlaceOfDelivery() != null) { - logger.info("delOutList" + gson.toJson(deliveryOutcome)); - IncentiveActivity incentiveActivityJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY1 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 1) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); + } } } - } + IncentiveActivity incentiveActivityJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY3 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 3) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY3); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); + } + } + } - IncentiveActivity incentiveActivityJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY2 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 2) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY2); - if (deliveryOutcome.getPlaceOfDelivery() != null) { + IncentiveActivity incentiveActivityJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY4 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 4) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY4); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); + } } } + } + if(deliveryOutcome.getDeliveryOutcome()!=null){ + if(!beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).isEmpty()){ + RMNCHBeneficiaryDetailsRmnch rmnchBeneficiaryDetailsRmnch = beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).get(0); + LocalDate marriageDate = rmnchBeneficiaryDetailsRmnch.getDateMarriage() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate deliveryDate = deliveryOutcome.getDateOfDelivery() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + long years = ChronoUnit.YEARS.between(marriageDate, deliveryDate); + if (years >= 2 && !rmnchBeneficiaryDetailsRmnch.getDoYouHavechildren()) { + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.FAMILY_PLANNING.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + - IncentiveActivity incentiveActivityJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY3 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 3) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY3); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); } + } + + + } - IncentiveActivity incentiveActivityJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY4 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 4) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY4); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); + if(deliveryOutcome.getDeliveryOutcome()!=null){ + if(!beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).isEmpty()){ + RMNCHBeneficiaryDetailsRmnch rmnchBeneficiaryDetailsRmnch = beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).get(0); + LocalDate marriageDate = rmnchBeneficiaryDetailsRmnch.getDateMarriage() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate deliveryDate = deliveryOutcome.getDateOfDelivery() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + long years = ChronoUnit.YEARS.between(marriageDate, deliveryDate); + + if (years >= 3 && rmnchBeneficiaryDetailsRmnch.getDoYouHavechildren()) { + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.FAMILY_PLANNING.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + } } + + + } - } + + }); + } - }); // JSY_ANC_URBAN // JSY_INST_URBAN @@ -212,7 +308,41 @@ private void createIncentiveRecordforJsy(DeliveryOutcome delOutList, Long benId, try { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getDateOfDelivery(), benId,userRepo.getUserIdByName(delOutList.getUpdatedBy())); + + + if (record == null) { + logger.info("setStartDate" + delOutList.getDateOfDelivery()); + logger.info("setCreatedDate" + delOutList.getCreatedDate()); + record = new IncentiveActivityRecord(); + record.setActivityId(immunizationActivity.getId()); + record.setCreatedDate(delOutList.getDateOfDelivery()); + record.setCreatedBy(delOutList.getCreatedBy()); + record.setStartDate(delOutList.getDateOfDelivery()); + record.setEndDate(delOutList.getDateOfDelivery()); + record.setUpdatedDate(delOutList.getDateOfDelivery()); + record.setUpdatedBy(delOutList.getCreatedBy()); + record.setBenId(benId); + record.setAshaId(userRepo.getUserIdByName(delOutList.getUpdatedBy())); + record.setAmount(Long.valueOf(immunizationActivity.getRate())); + recordRepo.save(record); + } else { + logger.info("benId:" + record.getId()); + + } + } catch (Exception e) { + logger.error("JSY Incentive:", e); + } + + + } + + private void createIncentiveRecordforYearGap(DeliveryOutcome delOutList, Long benId, IncentiveActivity immunizationActivity) { + logger.info("benId" + benId); + + try { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getDateOfDelivery(), benId,userRepo.getUserIdByName(delOutList.getUpdatedBy())); if (record == null) { @@ -224,7 +354,7 @@ record = new IncentiveActivityRecord(); record.setCreatedBy(delOutList.getCreatedBy()); record.setStartDate(delOutList.getDateOfDelivery()); record.setEndDate(delOutList.getDateOfDelivery()); - record.setUpdatedDate(delOutList.getCreatedDate()); + record.setUpdatedDate(delOutList.getDateOfDelivery()); record.setUpdatedBy(delOutList.getCreatedBy()); record.setBenId(benId); record.setAshaId(userRepo.getUserIdByName(delOutList.getUpdatedBy())); diff --git a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java index bc7800385..e6a69ba22 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java @@ -25,12 +25,21 @@ package com.iemr.flw.service.impl; import com.fasterxml.jackson.databind.ObjectMapper; -import com.iemr.flw.controller.CoupleController; +import com.iemr.flw.domain.identity.RMNCHBeneficiaryDetailsRmnch; import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.DiseaseType; +import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; +import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.DiseaseControlService; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; +import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -42,6 +51,7 @@ import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; + import org.modelmapper.ModelMapper; @Service @@ -77,10 +87,23 @@ public class DiseaseControlServiceImpl implements DiseaseControlService { private MosquitoNetRepository mosquitoNetRepository; + @Autowired + private ChronicDiseaseVisitRepository chronicDiseaseVisitRepository; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private IncentiveLogicService incentiveLogicService; + + @Autowired + private UserService userService; + @Autowired + private BeneficiaryRepo beneficiaryRepo; - private final Logger logger = LoggerFactory.getLogger(CoupleController.class); + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); @Override public String saveMalaria(MalariaDTO diseaseControlDTO) { @@ -102,7 +125,7 @@ public String saveMalaria(MalariaDTO diseaseControlDTO) { @Override public String saveKalaAzar(KalaAzarDTO diseaseControlDTO) { - logger.info("Save request: "+diseaseControlDTO.toString()); + logger.info("Save request: " + diseaseControlDTO.toString()); for (DiseaseKalaAzarDTO diseaseControlData : diseaseControlDTO.getKalaAzarLists()) { if (diseaseKalaAzarRepository.findByBenId(diseaseControlData.getBenId()).isPresent()) { return updateKalaAzarDisease(diseaseControlData); @@ -268,6 +291,7 @@ private String updateFilaria(DiseaseFilariasisDTO diseaseControlData) { @Override + @Transactional public String saveLeprosy(LeprosyDTO diseaseControlDTO) { for (DiseaseLeprosyDTO diseaseControlData : diseaseControlDTO.getLeprosyLists()) { if (diseaseLeprosyRepository.findByBenId(diseaseControlData.getBenId()).isPresent()) { @@ -276,7 +300,23 @@ public String saveLeprosy(LeprosyDTO diseaseControlDTO) { if (diseaseControlDTO.getUserId() != null) { diseaseControlData.setUserId(diseaseControlDTO.getUserId()); } - diseaseLeprosyRepository.save(saveLeprosyData(diseaseControlData)); + ScreeningLeprosy screeningLeprosy = diseaseLeprosyRepository.save(saveLeprosyData(diseaseControlData)); + if(screeningLeprosy.getIsConfirmed()){ + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForIdentificationLeprosy( + screeningLeprosy.getBenId(), + screeningLeprosy.getHomeVisitDate(), + screeningLeprosy.getHomeVisitDate(), + diseaseControlDTO.getUserId()); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + } + return "Data add successfully"; } @@ -313,46 +353,54 @@ private LeprosyFollowUp saveLeprosyFollowUpData(LeprosyFollowUpDTO data) { entity.setModifiedBy(data.getModifiedBy()); entity.setLastModDate( data.getLastModDate() != null ? data.getLastModDate() : new Timestamp(System.currentTimeMillis())); - + if(!leprosyFollowUpRepository.findByBenId(entity.getBenId()).isEmpty()){ + if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=6 && leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()<=12){ + Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForLeprosyPaucibacillaryConfirmed( + entity.getBenId(), + entity.getTreatmentEndDate(), + entity.getTreatmentEndDate(), + userId); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + } + } + + if(!leprosyFollowUpRepository.findByBenId(entity.getBenId()).isEmpty()){ + if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=12){ + Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForLeprosyMultibacillaryConfirmed( + entity.getBenId(), + entity.getTreatmentEndDate(), + entity.getTreatmentEndDate(), + userId); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + } + } return entity; } - private String updateLeprosyFollowUpData(LeprosyFollowUpDTO data, LeprosyFollowUp entity) { - entity.setVisitNumber(data.getVisitNumber()); - entity.setFollowUpDate(data.getFollowUpDate()); - entity.setTreatmentStatus(data.getTreatmentStatus()); - entity.setMdtBlisterPackReceived(data.getMdtBlisterPackReceived()); - entity.setTreatmentCompleteDate(data.getTreatmentCompleteDate()); - entity.setRemarks(data.getRemarks()); - entity.setHomeVisitDate(data.getHomeVisitDate()); - entity.setLeprosySymptoms(data.getLeprosySymptoms()); - entity.setTypeOfLeprosy(data.getTypeOfLeprosy()); - entity.setLeprosySymptomsPosition(data.getLeprosySymptomsPosition()); - entity.setVisitLabel(data.getVisitLabel()); - entity.setLeprosyStatus(data.getLeprosyStatus()); - entity.setReferredTo(data.getReferredTo()); - entity.setReferToName(data.getReferToName()); - entity.setTreatmentEndDate(data.getTreatmentEndDate()); - entity.setMdtBlisterPackRecived(data.getMdtBlisterPackRecived()); - entity.setTreatmentStartDate(data.getTreatmentStartDate()); - - // Update audit info - entity.setModifiedBy(data.getModifiedBy()); - entity.setLastModDate( - data.getLastModDate() != null ? data.getLastModDate() : new Timestamp(System.currentTimeMillis())); - - leprosyFollowUpRepository.save(entity); - return "Follow-up data updated successfully"; - } - @Override public String saveLeprosyFollowUp(LeprosyFollowUpDTO dto) { if (dto == null) return "Invalid data"; - LeprosyFollowUp entity = saveLeprosyFollowUpData(dto); - leprosyFollowUpRepository.save(entity); - return "Follow-up data added successfully"; - + LeprosyFollowUp entity = saveLeprosyFollowUpData(dto); + leprosyFollowUpRepository.save(entity); + return "Follow-up data added successfully"; + } @Override @@ -369,7 +417,6 @@ public List getAllLeprosyData(String createdBy) { return dtos; } - @Override public List getAllLeprosyFollowUpData(String createdBy) { logger.info("Fetching leprosy data for createdBy: " + createdBy); @@ -390,47 +437,102 @@ public Object getAllMalaria(GetDiseaseRequestHandler getDiseaseRequestHandler) { // Fetch and filter malaria disease records List filteredList = diseaseMalariaRepository.findAll().stream() - .filter(disease -> Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getUserId())) + .filter(disease -> Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getAshaId())) .collect(Collectors.toList()); // Check if the list is empty if (filteredList.isEmpty()) { - return Collections.singletonMap("message", "No data found for Malaria."); + return filteredList; } // Map to DTOs List dtoList = filteredList.stream().map(disease -> { + DiseaseMalariaDTO dto = new DiseaseMalariaDTO(); - // Map fields from DiseaseMalaria to DTO - dto.setId(disease.getId()); - dto.setBenId(disease.getBenId()); - dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); - dto.setScreeningDate(disease.getScreeningDate()); - dto.setBeneficiaryStatus(disease.getBeneficiaryStatus()); - dto.setDateOfDeath(disease.getDateOfDeath()); - dto.setPlaceOfDeath(disease.getPlaceOfDeath()); - dto.setOtherPlaceOfDeath(disease.getOtherPlaceOfDeath()); - dto.setReasonForDeath(disease.getReasonForDeath()); - dto.setOtherReasonForDeath(disease.getOtherReasonForDeath()); - dto.setCaseStatus(disease.getCaseStatus()); - dto.setRapidDiagnosticTest(disease.getRapidDiagnosticTest()); - dto.setDateOfRdt(disease.getDateOfRdt()); - dto.setSlideTestPf(disease.getSlideTestPf()); - dto.setSlideTestPv(disease.getSlideTestPv()); - dto.setDateOfSlideTest(disease.getDateOfSlideTest()); - dto.setSlideNo(disease.getSlideNo()); - dto.setReferredTo(disease.getReferredTo()); - dto.setOtherReferredFacility(disease.getOtherReferredFacility()); - dto.setRemarks(disease.getRemarks()); - dto.setDateOfVisitBySupervisor(disease.getDateOfVisitBySupervisor()); - dto.setUserId(disease.getUserId()); - dto.setDiseaseTypeId(disease.getDiseaseTypeId()); - - // Parse symptoms (if present) + if (disease.getId() != null) + dto.setId(disease.getId()); + + if (disease.getBenId() != null) + dto.setBenId(disease.getBenId()); + + if (disease.getHouseHoldDetailsId() != null) + dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); + + if (disease.getScreeningDate() != null) + dto.setScreeningDate(disease.getScreeningDate()); + + if (disease.getBeneficiaryStatus() != null && !disease.getBeneficiaryStatus().trim().isEmpty()) + dto.setBeneficiaryStatus(disease.getBeneficiaryStatus()); + + if (disease.getDateOfDeath() != null) + dto.setDateOfDeath(disease.getDateOfDeath()); + + if (disease.getPlaceOfDeath() != null && !disease.getPlaceOfDeath().trim().isEmpty()) + dto.setPlaceOfDeath(disease.getPlaceOfDeath()); + + if (disease.getOtherPlaceOfDeath() != null && !disease.getOtherPlaceOfDeath().trim().isEmpty()) + dto.setOtherPlaceOfDeath(disease.getOtherPlaceOfDeath()); + + if (disease.getReasonForDeath() != null && !disease.getReasonForDeath().trim().isEmpty()) + dto.setReasonForDeath(disease.getReasonForDeath()); + + if (disease.getOtherReasonForDeath() != null && !disease.getOtherReasonForDeath().trim().isEmpty()) + dto.setOtherReasonForDeath(disease.getOtherReasonForDeath()); + + if (disease.getCaseStatus() != null && !disease.getCaseStatus().trim().isEmpty()) + dto.setCaseStatus(disease.getCaseStatus()); + + if (disease.getRapidDiagnosticTest() != null) + dto.setRapidDiagnosticTest(disease.getRapidDiagnosticTest()); + + if (disease.getDateOfRdt() != null) + dto.setDateOfRdt(disease.getDateOfRdt()); + + if (disease.getSlideTestPf() != null) + dto.setSlideTestPf(disease.getSlideTestPf()); + + if (disease.getSlideTestPv() != null) + dto.setSlideTestPv(disease.getSlideTestPv()); + + if (disease.getDateOfSlideTest() != null) + dto.setDateOfSlideTest(disease.getDateOfSlideTest()); + + if (disease.getSlideNo() != null && !disease.getSlideNo().trim().isEmpty()) + dto.setSlideNo(disease.getSlideNo()); + + if (disease.getReferredTo() != null) + dto.setReferredTo(disease.getReferredTo()); + + if (disease.getOtherReferredFacility() != null && !disease.getOtherReferredFacility().trim().isEmpty()) + dto.setOtherReferredFacility(disease.getOtherReferredFacility()); + + if (disease.getRemarks() != null && !disease.getRemarks().trim().isEmpty()) + dto.setRemarks(disease.getRemarks()); + + if (disease.getMalariaSlideTestType() != null && !disease.getMalariaSlideTestType().trim().isEmpty()) + dto.setMalariaSlideTestType(disease.getMalariaSlideTestType()); + + if (disease.getMalariaTestType() != null && !disease.getMalariaTestType().trim().isEmpty()) + dto.setMalariaTestType(disease.getMalariaTestType()); + + if (disease.getDateOfVisitBySupervisor() != null) + dto.setDateOfVisitBySupervisor(disease.getDateOfVisitBySupervisor()); + + if (disease.getUserId() != null) + dto.setUserId(disease.getUserId()); + + if (disease.getDiseaseTypeId() != null) + dto.setDiseaseTypeId(disease.getDiseaseTypeId()); + + // Symptoms JSON try { - if (disease.getSymptoms() != null && !disease.getSymptoms().isEmpty()) { - MalariaSymptomsDTO symptomsDTO = objectMapper.readValue(disease.getSymptoms(), MalariaSymptomsDTO.class); + if (disease.getSymptoms() != null && + !disease.getSymptoms().trim().isEmpty()) { + + MalariaSymptomsDTO symptomsDTO = + objectMapper.readValue(disease.getSymptoms(), MalariaSymptomsDTO.class); + dto.setFeverMoreThanTwoWeeks(symptomsDTO.isFeverMoreThanTwoWeeks()); dto.setFluLikeIllness(symptomsDTO.isFluLikeIllness()); dto.setShakingChills(symptomsDTO.isShakingChills()); @@ -442,7 +544,8 @@ public Object getAllMalaria(GetDiseaseRequestHandler getDiseaseRequestHandler) { dto.setDiarrhea(symptomsDTO.isDiarrhea()); } } catch (Exception e) { - throw new RuntimeException("Error parsing symptoms JSON for Malaria Disease ID: " + disease.getId(), e); + logger.error("Error parsing symptoms for diseaseId={}", + disease.getId(), e); } return dto; @@ -478,40 +581,87 @@ public Object getAllKalaAzar(GetDiseaseRequestHandler getDiseaseRequestHandler) // Fetch and filter Kala Azar disease records List filteredList = diseaseKalaAzarRepository.findAll().stream() - .filter(disease -> (Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getUserId()))) + .filter(disease -> (Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getAshaId()))) .collect(Collectors.toList()); // Check if the list is empty if (filteredList.isEmpty()) { - return Collections.singletonMap("message", "No data found for Kala Azar."); + return filteredList; } // Map to DTOs List dtoList = filteredList.stream().map(disease -> { + DiseaseKalaAzarDTO dto = new DiseaseKalaAzarDTO(); - dto.setId(disease.getId()); - dto.setBenId(disease.getBenId()); - dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); - dto.setVisitDate(disease.getVisitDate()); - dto.setBeneficiaryStatus(disease.getBeneficiaryStatus()); - dto.setDateOfDeath(disease.getDateOfDeath()); - dto.setPlaceOfDeath(disease.getPlaceOfDeath()); - dto.setOtherPlaceOfDeath(disease.getOtherPlaceOfDeath()); - dto.setReasonForDeath(disease.getReasonForDeath()); - dto.setOtherReasonForDeath(disease.getOtherReasonForDeath()); - dto.setKalaAzarCaseStatus(disease.getKalaAzarCaseStatus()); - dto.setKalaAzarCaseCount(disease.getKalaAzarCaseCount()); - dto.setRapidDiagnosticTest(disease.getRapidDiagnosticTest()); - dto.setDateOfRdt(disease.getDateOfRdt()); - dto.setFollowUpPoint(disease.getFollowUpPoint()); - dto.setReferredTo(disease.getReferredTo()); - dto.setOtherReferredFacility(disease.getOtherReferredFacility()); - dto.setCreatedDate(disease.getCreatedDate()); - dto.setCreatedBy(disease.getCreatedBy()); - dto.setBeneficiaryStatusId(disease.getBeneficiaryStatusId()); - dto.setReferToName(disease.getReferToName()); - dto.setUserId(disease.getUserId()); - dto.setDiseaseTypeId(disease.getDiseaseTypeId()); + + if (disease.getId() != null) + dto.setId(disease.getId()); + + if (disease.getBenId() != null) + dto.setBenId(disease.getBenId()); + + if (disease.getHouseHoldDetailsId() != null) + dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); + + if (disease.getVisitDate() != null) + dto.setVisitDate(disease.getVisitDate()); + + if (disease.getBeneficiaryStatus() != null && !disease.getBeneficiaryStatus().trim().isEmpty()) + dto.setBeneficiaryStatus(disease.getBeneficiaryStatus()); + + if (disease.getDateOfDeath() != null) + dto.setDateOfDeath(disease.getDateOfDeath()); + + if (disease.getPlaceOfDeath() != null && !disease.getPlaceOfDeath().trim().isEmpty()) + dto.setPlaceOfDeath(disease.getPlaceOfDeath()); + + if (disease.getOtherPlaceOfDeath() != null && !disease.getOtherPlaceOfDeath().trim().isEmpty()) + dto.setOtherPlaceOfDeath(disease.getOtherPlaceOfDeath()); + + if (disease.getReasonForDeath() != null && !disease.getReasonForDeath().trim().isEmpty()) + dto.setReasonForDeath(disease.getReasonForDeath()); + + if (disease.getOtherReasonForDeath() != null && !disease.getOtherReasonForDeath().trim().isEmpty()) + dto.setOtherReasonForDeath(disease.getOtherReasonForDeath()); + + if (disease.getKalaAzarCaseStatus() != null && !disease.getKalaAzarCaseStatus().trim().isEmpty()) + dto.setKalaAzarCaseStatus(disease.getKalaAzarCaseStatus()); + + if (disease.getKalaAzarCaseCount() != null) + dto.setKalaAzarCaseCount(disease.getKalaAzarCaseCount()); + + if (disease.getRapidDiagnosticTest() != null) + dto.setRapidDiagnosticTest(disease.getRapidDiagnosticTest()); + + if (disease.getDateOfRdt() != null) + dto.setDateOfRdt(disease.getDateOfRdt()); + + if (disease.getFollowUpPoint() != null) + dto.setFollowUpPoint(disease.getFollowUpPoint()); + + if (disease.getReferredTo() != null && !disease.getReferredTo().trim().isEmpty()) + dto.setReferredTo(disease.getReferredTo()); + + if (disease.getOtherReferredFacility() != null && !disease.getOtherReferredFacility().trim().isEmpty()) + dto.setOtherReferredFacility(disease.getOtherReferredFacility()); + + if (disease.getCreatedDate() != null) + dto.setCreatedDate(disease.getCreatedDate()); + + if (disease.getCreatedBy() != null && !disease.getCreatedBy().trim().isEmpty()) + dto.setCreatedBy(disease.getCreatedBy()); + + if (disease.getBeneficiaryStatusId() != null) + dto.setBeneficiaryStatusId(disease.getBeneficiaryStatusId()); + + if (disease.getReferToName() != null && !disease.getReferToName().trim().isEmpty()) + dto.setReferToName(disease.getReferToName()); + + if (disease.getUserId() != null) + dto.setUserId(disease.getUserId()); + + if (disease.getDiseaseTypeId() != null) + dto.setDiseaseTypeId(disease.getDiseaseTypeId()); return dto; }).collect(Collectors.toList()); @@ -522,17 +672,17 @@ public Object getAllKalaAzar(GetDiseaseRequestHandler getDiseaseRequestHandler) public Object getAllKalaAES(GetDiseaseRequestHandler getDiseaseRequestHandler) { if (diseaseAESJERepository.findAll().isEmpty()) { - return Collections.singletonMap("message", "No data found for AES."); + return diseaseAESJERepository.findAll(); } - return diseaseAESJERepository.findAll().stream().filter(diseaseAesje -> Objects.equals(diseaseAesje.getUserId(), getDiseaseRequestHandler.getUserId())).collect(Collectors.toList()); + return diseaseAESJERepository.findAll().stream().filter(diseaseAesje -> Objects.equals(diseaseAesje.getUserId(), getDiseaseRequestHandler.getAshaId())).collect(Collectors.toList()); } public Object getAllFilaria(GetDiseaseRequestHandler getDiseaseRequestHandler) { // Fetch and filter Filaria disease records - List filteredList = diseaseFilariasisRepository.findAll().stream().filter(screeningFilariasis -> Objects.equals(screeningFilariasis.getUserId(), getDiseaseRequestHandler.getUserId())).collect(Collectors.toList()); + List filteredList = diseaseFilariasisRepository.findAll().stream().filter(screeningFilariasis -> Objects.equals(screeningFilariasis.getUserId(), getDiseaseRequestHandler.getAshaId())).collect(Collectors.toList()); // Check if the list is empty if (filteredList.isEmpty()) { @@ -541,23 +691,58 @@ public Object getAllFilaria(GetDiseaseRequestHandler getDiseaseRequestHandler) { // Map to DTOs List dtoList = filteredList.stream().map(disease -> { + DiseaseFilariasisDTO dto = new DiseaseFilariasisDTO(); - dto.setId(disease.getId()); - dto.setBenId(disease.getBenId()); - dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); - dto.setSufferingFromFilariasis(disease.getSufferingFromFilariasis()); - dto.setAffectedBodyPart(disease.getAffectedBodyPart()); - dto.setMdaHomeVisitDate(disease.getMdaHomeVisitDate()); - dto.setDoseStatus(disease.getDoseStatus()); - dto.setFilariasisCaseCount(disease.getFilariasisCaseCount()); - dto.setOtherDoseStatusDetails(disease.getOtherDoseStatusDetails()); - dto.setMedicineSideEffect(disease.getMedicineSideEffect()); - dto.setOtherSideEffectDetails(disease.getOtherSideEffectDetails()); - dto.setCreatedDate(disease.getCreatedDate()); - dto.setCreatedBy(disease.getCreatedBy()); - dto.setUserId(disease.getUserId()); + + if (disease.getId() != null) + dto.setId(disease.getId()); + + if (disease.getBenId() != null) + dto.setBenId(disease.getBenId()); + + if (disease.getHouseHoldDetailsId() != null) + dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); + + if (disease.getSufferingFromFilariasis() != null) + dto.setSufferingFromFilariasis(disease.getSufferingFromFilariasis()); + + if (disease.getAffectedBodyPart() != null && + !disease.getAffectedBodyPart().trim().isEmpty()) + dto.setAffectedBodyPart(disease.getAffectedBodyPart()); + + if (disease.getMdaHomeVisitDate() != null) + dto.setMdaHomeVisitDate(disease.getMdaHomeVisitDate()); + + if (disease.getDoseStatus() != null && + !disease.getDoseStatus().trim().isEmpty()) + dto.setDoseStatus(disease.getDoseStatus()); + + if (disease.getFilariasisCaseCount() != null) + dto.setFilariasisCaseCount(disease.getFilariasisCaseCount()); + + if (disease.getOtherDoseStatusDetails() != null && + !disease.getOtherDoseStatusDetails().trim().isEmpty()) + dto.setOtherDoseStatusDetails(disease.getOtherDoseStatusDetails()); + + if (disease.getMedicineSideEffect() != null) + dto.setMedicineSideEffect(disease.getMedicineSideEffect()); + + if (disease.getOtherSideEffectDetails() != null && + !disease.getOtherSideEffectDetails().trim().isEmpty()) + dto.setOtherSideEffectDetails(disease.getOtherSideEffectDetails()); + + if (disease.getCreatedDate() != null) + dto.setCreatedDate(disease.getCreatedDate()); + + if (disease.getCreatedBy() != null && + !disease.getCreatedBy().trim().isEmpty()) + dto.setCreatedBy(disease.getCreatedBy()); + + if (disease.getUserId() != null) + dto.setUserId(disease.getUserId()); return dto; + }).collect(Collectors.toList()); return dtoList; @@ -568,30 +753,55 @@ public Object getAllLeprosy(GetDiseaseRequestHandler getDiseaseRequestHandler) { // Fetch and filter Leprosy disease records List filteredList = diseaseLeprosyRepository.findAll().stream() - .filter(disease -> Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getUserId())) + .filter(disease -> Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getAshaId())) .collect(Collectors.toList()); // Check if the list is empty if (filteredList.isEmpty()) { - return Collections.singletonMap("message", "No data found for Leprosy."); + return filteredList; } // Map to DTOs List dtoList = filteredList.stream().map(disease -> { DiseaseLeprosyDTO dto = new DiseaseLeprosyDTO(); - dto.setId(disease.getId()); - dto.setBenId(disease.getBenId()); - dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); - dto.setHomeVisitDate(disease.getHomeVisitDate()); - dto.setLeprosyStatus(disease.getLeprosyStatus()); - dto.setReferredTo(disease.getReferredTo()); - dto.setOtherReferredTo(disease.getOtherReferredTo()); - dto.setLeprosyStatusDate(disease.getLeprosyStatusDate()); - dto.setTypeOfLeprosy(disease.getTypeOfLeprosy()); - dto.setFollowUpDate(disease.getFollowUpDate()); - dto.setBeneficiaryStatus(disease.getLeprosyStatus()); - dto.setRemark(disease.getRemark()); - dto.setUserId(disease.getUserId()); + if (disease.getId() != null) + dto.setId(disease.getId()); + + if (disease.getBenId() != null) + dto.setBenId(disease.getBenId()); + + if (disease.getHouseHoldDetailsId() != null) + dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); + + if (disease.getHomeVisitDate() != null) + dto.setHomeVisitDate(disease.getHomeVisitDate()); + + if (disease.getLeprosyStatus() != null && !disease.getLeprosyStatus().trim().isEmpty()) + dto.setLeprosyStatus(disease.getLeprosyStatus()); + + if (disease.getReferredTo() != null && !disease.getReferredTo().trim().isEmpty()) + dto.setReferredTo(disease.getReferredTo()); + + if (disease.getOtherReferredTo() != null && !disease.getOtherReferredTo().trim().isEmpty()) + dto.setOtherReferredTo(disease.getOtherReferredTo()); + + if (disease.getLeprosyStatusDate() != null) + dto.setLeprosyStatusDate(disease.getLeprosyStatusDate()); + + if (disease.getTypeOfLeprosy() != null && !disease.getTypeOfLeprosy().trim().isEmpty()) + dto.setTypeOfLeprosy(disease.getTypeOfLeprosy()); + + if (disease.getFollowUpDate() != null) + dto.setFollowUpDate(disease.getFollowUpDate()); + + if (disease.getLeprosyStatus() != null && !disease.getLeprosyStatus().trim().isEmpty()) + dto.setBeneficiaryStatus(disease.getLeprosyStatus()); + + if (disease.getRemark() != null && !disease.getRemark().trim().isEmpty()) + dto.setRemark(disease.getRemark()); + + if (disease.getUserId() != null) + dto.setUserId(disease.getUserId()); return dto; @@ -602,7 +812,7 @@ public Object getAllLeprosy(GetDiseaseRequestHandler getDiseaseRequestHandler) { private ScreeningKalaAzar saveKalaAzarDisease(DiseaseKalaAzarDTO dto) { - logger.info("KalaAzarRequest: "+dto); + logger.info("KalaAzarRequest: " + dto); ScreeningKalaAzar entity = new ScreeningKalaAzar(); entity.setBenId(dto.getBenId()); @@ -687,7 +897,10 @@ private ScreeningLeprosy saveLeprosyData(DiseaseLeprosyDTO diseaseControlData) { diseaseLeprosy.setDiseaseTypeId(diseaseControlData.getDiseaseTypeId()); diseaseLeprosy.setOtherReferredTo(diseaseControlData.getOtherReferredTo()); diseaseLeprosy.setLeprosyStatusDate(diseaseControlData.getLeprosyStatusDate()); - diseaseLeprosy.setTypeOfLeprosy(diseaseControlData.getTypeOfLeprosy()); + if(diseaseControlData.getTypeOfLeprosy()!=null){ + diseaseLeprosy.setTypeOfLeprosy(diseaseControlData.getTypeOfLeprosy()); + + } diseaseLeprosy.setFollowUpDate(diseaseControlData.getFollowUpDate()); diseaseLeprosy.setBeneficiaryStatus(diseaseControlData.getBeneficiaryStatus()); diseaseLeprosy.setBeneficiaryStatusId(diseaseControlData.getBeneficiaryStatusId()); @@ -717,6 +930,33 @@ private ScreeningLeprosy saveLeprosyData(DiseaseLeprosyDTO diseaseControlData) { diseaseLeprosy.setModifiedBy(diseaseControlData.getModifiedBy()); diseaseLeprosy.setLastModDate(diseaseControlData.getLastModDate()); + diseaseLeprosy.setRecurrentUlcerationId(diseaseControlData.getRecurrentUlcerationId()); + diseaseLeprosy.setRecurrentTinglingId(diseaseControlData.getRecurrentTinglingId()); + diseaseLeprosy.setHypopigmentedPatchId(diseaseControlData.getHypopigmentedPatchId()); + diseaseLeprosy.setThickenedSkinId(diseaseControlData.getThickenedSkinId()); + diseaseLeprosy.setSkinNodulesId(diseaseControlData.getSkinNodulesId()); + diseaseLeprosy.setSkinPatchDiscolorationId(diseaseControlData.getSkinPatchDiscolorationId()); + diseaseLeprosy.setRecurrentNumbnessId(diseaseControlData.getRecurrentNumbnessId()); + diseaseLeprosy.setClawingFingersId(diseaseControlData.getClawingFingersId()); + diseaseLeprosy.setTinglingNumbnessExtremitiesId(diseaseControlData.getTinglingNumbnessExtremitiesId()); + diseaseLeprosy.setInabilityCloseEyelidId(diseaseControlData.getInabilityCloseEyelidId()); + diseaseLeprosy.setDifficultyHoldingObjectsId(diseaseControlData.getDifficultyHoldingObjectsId()); + diseaseLeprosy.setWeaknessFeetId(diseaseControlData.getWeaknessFeetId()); + + diseaseLeprosy.setRecurrentUlceration(diseaseControlData.getRecurrentUlceration()); + diseaseLeprosy.setRecurrentTingling(diseaseControlData.getRecurrentTingling()); + diseaseLeprosy.setHypopigmentedPatch(diseaseControlData.getHypopigmentedPatch()); + diseaseLeprosy.setThickenedSkin(diseaseControlData.getThickenedSkin()); + diseaseLeprosy.setSkinNodules(diseaseControlData.getSkinNodules()); + diseaseLeprosy.setSkinPatchDiscoloration(diseaseControlData.getSkinPatchDiscoloration()); + diseaseLeprosy.setRecurrentNumbness(diseaseControlData.getRecurrentNumbness()); + diseaseLeprosy.setClawingFingers(diseaseControlData.getClawingFingers()); + diseaseLeprosy.setTinglingNumbnessExtremities(diseaseControlData.getTinglingNumbnessExtremities()); + diseaseLeprosy.setInabilityCloseEyelid(diseaseControlData.getInabilityCloseEyelid()); + diseaseLeprosy.setDifficultyHoldingObjects(diseaseControlData.getDifficultyHoldingObjects()); + diseaseLeprosy.setWeaknessFeet(diseaseControlData.getWeaknessFeet()); + + return diseaseLeprosy; } @@ -761,6 +1001,33 @@ private String updateLeprosyData(DiseaseLeprosyDTO diseaseControlData) { existingDiseaseLeprosy.setModifiedBy(diseaseControlData.getModifiedBy()); existingDiseaseLeprosy.setLastModDate(diseaseControlData.getLastModDate()); + existingDiseaseLeprosy.setRecurrentUlcerationId(diseaseControlData.getRecurrentUlcerationId()); + existingDiseaseLeprosy.setRecurrentTinglingId(diseaseControlData.getRecurrentTinglingId()); + existingDiseaseLeprosy.setHypopigmentedPatchId(diseaseControlData.getHypopigmentedPatchId()); + existingDiseaseLeprosy.setThickenedSkinId(diseaseControlData.getThickenedSkinId()); + existingDiseaseLeprosy.setSkinNodulesId(diseaseControlData.getSkinNodulesId()); + existingDiseaseLeprosy.setSkinPatchDiscolorationId(diseaseControlData.getSkinPatchDiscolorationId()); + existingDiseaseLeprosy.setRecurrentNumbnessId(diseaseControlData.getRecurrentNumbnessId()); + existingDiseaseLeprosy.setClawingFingersId(diseaseControlData.getClawingFingersId()); + existingDiseaseLeprosy.setTinglingNumbnessExtremitiesId(diseaseControlData.getTinglingNumbnessExtremitiesId()); + existingDiseaseLeprosy.setInabilityCloseEyelidId(diseaseControlData.getInabilityCloseEyelidId()); + existingDiseaseLeprosy.setDifficultyHoldingObjectsId(diseaseControlData.getDifficultyHoldingObjectsId()); + existingDiseaseLeprosy.setWeaknessFeetId(diseaseControlData.getWeaknessFeetId()); + + existingDiseaseLeprosy.setRecurrentUlceration(diseaseControlData.getRecurrentUlceration()); + existingDiseaseLeprosy.setRecurrentTingling(diseaseControlData.getRecurrentTingling()); + existingDiseaseLeprosy.setHypopigmentedPatch(diseaseControlData.getHypopigmentedPatch()); + existingDiseaseLeprosy.setThickenedSkin(diseaseControlData.getThickenedSkin()); + existingDiseaseLeprosy.setSkinNodules(diseaseControlData.getSkinNodules()); + existingDiseaseLeprosy.setSkinPatchDiscoloration(diseaseControlData.getSkinPatchDiscoloration()); + existingDiseaseLeprosy.setRecurrentNumbness(diseaseControlData.getRecurrentNumbness()); + existingDiseaseLeprosy.setClawingFingers(diseaseControlData.getClawingFingers()); + existingDiseaseLeprosy.setTinglingNumbnessExtremities(diseaseControlData.getTinglingNumbnessExtremities()); + existingDiseaseLeprosy.setInabilityCloseEyelid(diseaseControlData.getInabilityCloseEyelid()); + existingDiseaseLeprosy.setDifficultyHoldingObjects(diseaseControlData.getDifficultyHoldingObjects()); + existingDiseaseLeprosy.setWeaknessFeet(diseaseControlData.getWeaknessFeet()); + + diseaseLeprosyRepository.save(existingDiseaseLeprosy); // Return the updated entity return "Data update successfully"; @@ -789,6 +1056,8 @@ private ScreeningMalaria saveMalariaDisease(DiseaseMalariaDTO requestData) { diseaseScreening.setSlideTestPv(requestData.getSlideTestPv()); diseaseScreening.setDateOfSlideTest(requestData.getDateOfSlideTest()); diseaseScreening.setSlideNo(requestData.getSlideNo()); + diseaseScreening.setMalariaTestType(requestData.getMalariaTestType()); + diseaseScreening.setMalariaSlideTestType(requestData.getMalariaSlideTestType()); diseaseScreening.setReferredTo(requestData.getReferredTo()); diseaseScreening.setOtherReferredFacility(requestData.getOtherReferredFacility()); diseaseScreening.setRemarks(requestData.getRemarks()); @@ -823,6 +1092,8 @@ private String updateMalariaDisease(DiseaseMalariaDTO requestData) { diseaseScreening.setSlideNo(requestData.getSlideNo()); diseaseScreening.setReferredTo(requestData.getReferredTo()); diseaseScreening.setOtherReferredFacility(requestData.getOtherReferredFacility()); + diseaseScreening.setMalariaSlideTestType(requestData.getMalariaSlideTestType()); + diseaseScreening.setMalariaTestType(requestData.getMalariaTestType()); diseaseScreening.setRemarks(requestData.getRemarks()); diseaseScreening.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); diseaseScreening.setDateOfVisitBySupervisor(requestData.getDateOfVisitBySupervisor()); @@ -861,8 +1132,10 @@ public List saveMosquitoMobilizationNet(List mos List entityList = mosquitoNetDTOList.stream().map(dto -> { MosquitoNetEntity entity = new MosquitoNetEntity(); + if(!beneficiaryRepo.findByHouseoldId(dto.getHouseHoldId()).isEmpty()){ + entity.setBeneficiaryId(beneficiaryRepo.findByHouseoldId(dto.getHouseHoldId()).get(0).getBenficieryid()); - entity.setBeneficiaryId(dto.getBeneficiaryId()); + } entity.setHouseHoldId(dto.getHouseHoldId()); // ✅ String → LocalDate conversion @@ -887,12 +1160,10 @@ public List saveMosquitoMobilizationNet(List mos }).collect(Collectors.toList()); - // ✅ Save all List savedEntities = mosquitoNetRepository.saveAll(entityList); - // ✅ Entity → DTO return return savedEntities.stream().map(entity -> { @@ -913,7 +1184,7 @@ public List saveMosquitoMobilizationNet(List mos if (dto.getFields() != null) { dto.getFields().setIs_net_distributed(entity.getIsNetDistributed()); } - + checkAndAddIncentives(entity); return dto; }).collect(Collectors.toList()); @@ -940,62 +1211,317 @@ public List getAllMosquitoMobilizationNet(Integer userId) { mosquitoNetListDTO.setIs_net_distributed(entity.getIsNetDistributed()); mosquitoNetListDTO.setVisit_date(entity.getVisitDate().format(formatter)); - dto.setFields(mosquitoNetListDTO); + dto.setFields(mosquitoNetListDTO); + return dto; }).collect(Collectors.toList()); } + private void checkAndAddIncentives(MosquitoNetEntity mosquitoNetEntity) { + Integer stateId = userService.getUserDetail(mosquitoNetEntity.getUserId()).getStateId(); + IncentiveActivity activityMobilizingMosquitoNets = incentivesRepo.findIncentiveMasterByNameAndGroup("MOSQUITO_NET_DISTRIBUTION_MOBILIZATION", GroupName.ACTIVITY.getDisplayName()); + if(stateId.equals(StateCode.CG.getStateCode())){ + addIncentive(activityMobilizingMosquitoNets, mosquitoNetEntity); + } + } private void checkAndAddIncentives(ScreeningMalaria diseaseScreening) { - IncentiveActivity diseaseScreeningActivity; - if (Objects.equals(diseaseScreening.getCaseStatus(), "Confirmed Case")) { - diseaseScreeningActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("MALARIA_1", "DISEASECONTROL"); + Integer stateId = userService.getUserDetail(diseaseScreening.getUserId()).getStateId(); + IncentiveActivity diseaseScreeningActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("NVBDCP_MALARIA_TREATMENT", GroupName.UMBRELLA_PROGRAMMES.getDisplayName()); + IncentiveActivity diseaseScreeningActivityCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NVBDCP_MALARIA_TREATMENT", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity incentiveActivityForCollectSlideAM = incentivesRepo.findIncentiveMasterByNameAndGroup("NVBDCP_SLIDE_COLLECTION", GroupName.UMBRELLA_PROGRAMMES.getDisplayName()); + IncentiveActivity incentiveActivityForCollectSlideCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NVBDCP_SLIDE_COLLECTION", GroupName.ACTIVITY.getDisplayName()); + + if (diseaseScreeningActivity != null) { + if(stateId.equals(StateCode.AM.getStateCode())){ + if (Objects.equals(diseaseScreening.getCaseStatus(), "Confirmed")) { + addIncentive(diseaseScreeningActivity, diseaseScreening); - } else { - diseaseScreeningActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("MALARIA_2", "DISEASECONTROL"); + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ + if (Objects.equals(diseaseScreening.getCaseStatus(), "Confirmed")) { + addIncentive(diseaseScreeningActivityCG, diseaseScreening); + + } + } } + if (diseaseScreening.getCaseStatus().equals("Suspected")) { + if (!diseaseScreening.getMalariaTestType().isEmpty()) { + if (stateId.equals(StateCode.AM.getStateCode())) { + if (incentiveActivityForCollectSlideAM != null) { + addIncentive(incentiveActivityForCollectSlideAM, diseaseScreening); - if (diseaseScreeningActivity != null) { + } + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + if (incentiveActivityForCollectSlideCG != null) { + addIncentive(incentiveActivityForCollectSlideCG, diseaseScreening); + + } + } + + + } + + } + } + private void addIncentive(IncentiveActivity diseaseScreeningActivity, MosquitoNetEntity diseaseScreening) { + + Timestamp visitTimestamp = + Timestamp.valueOf(diseaseScreening.getVisitDate().atStartOfDay()); + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId( + diseaseScreeningActivity.getId(), + visitTimestamp, + diseaseScreening.getBeneficiaryId(),diseaseScreening.getUserId()); + + if (record == null) { + + record = new IncentiveActivityRecord(); + + record.setActivityId(diseaseScreeningActivity.getId()); + record.setCreatedDate(visitTimestamp); + record.setCreatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setStartDate(visitTimestamp); + record.setEndDate(visitTimestamp); + record.setUpdatedDate(visitTimestamp); + record.setUpdatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setBenId(diseaseScreening.getBeneficiaryId().longValue()); + record.setAshaId(diseaseScreening.getUserId()); + record.setAmount(Long.valueOf(diseaseScreeningActivity.getRate())); + record.setIsEligible(true); + + recordRepo.save(record); + } + + } + + + private void addIncentive(IncentiveActivity diseaseScreeningActivity, ScreeningMalaria diseaseScreening) { + try { + Timestamp screeningTimestamp = diseaseScreening.getScreeningDate() != null + ? new Timestamp(diseaseScreening.getScreeningDate().getTime()) + : null; IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(diseaseScreeningActivity.getId(), Timestamp.valueOf(diseaseScreening.getCreatedDate().toString()), diseaseScreening.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(diseaseScreeningActivity.getId(), Timestamp.valueOf(diseaseScreening.getCreatedDate().toString()), diseaseScreening.getBenId().longValue(),diseaseScreening.getUserId()); if (record == null) { - if (Objects.equals(diseaseScreening.getCaseStatus(), "Confirmed Case")) { - record = new IncentiveActivityRecord(); - record.setActivityId(diseaseScreeningActivity.getId()); - record.setCreatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setCreatedBy(diseaseScreening.getCreatedBy()); - record.setStartDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setEndDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedBy(diseaseScreening.getCreatedBy()); - record.setBenId(diseaseScreening.getBenId().longValue()); - record.setAshaId(diseaseScreening.getUserId()); - record.setName(diseaseScreeningActivity.getName()); - record.setAmount(Long.valueOf(diseaseScreeningActivity.getRate())); - recordRepo.save(record); - } else { - record = new IncentiveActivityRecord(); - record.setActivityId(diseaseScreeningActivity.getId()); - record.setCreatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setCreatedBy(diseaseScreening.getCreatedBy()); - record.setStartDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setEndDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedBy(diseaseScreening.getCreatedBy()); - record.setBenId(diseaseScreening.getBenId().longValue()); - record.setName(diseaseScreeningActivity.getName()); - record.setAshaId(diseaseScreening.getUserId()); - record.setAmount(Long.valueOf(diseaseScreeningActivity.getRate())); - recordRepo.save(record); + record = new IncentiveActivityRecord(); + record.setActivityId(diseaseScreeningActivity.getId()); + record.setCreatedDate(screeningTimestamp); + record.setCreatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setStartDate(screeningTimestamp); + record.setEndDate(screeningTimestamp); + record.setUpdatedDate(screeningTimestamp); + record.setUpdatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setUpdatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setBenId(diseaseScreening.getBenId().longValue()); + record.setAshaId(diseaseScreening.getUserId()); + record.setAmount(Long.valueOf(diseaseScreeningActivity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + logger.info("Incentive for {}"+diseaseScreeningActivity.getDescription()); + + } + }catch (Exception e){ + logger.info("Fail to generate Incentive for {}"+diseaseScreeningActivity.getDescription()+ "Exception"+e.getMessage()); + + } + + } + + + @Override + public List saveChronicDiseaseVisit( + List requestList, String token) throws IEMRException { + Integer userId = jwtUtil.extractUserId(token); + String userName= userRepo.getUserNamedByUserId(userId); + + List responseList = new ArrayList<>(); + + for (ChronicDiseaseVisitDTO dto : requestList) { + + ChronicDiseaseVisitEntity entity = new ChronicDiseaseVisitEntity(); + + entity.setBenId(dto.getBenId()); + entity.setHhId(dto.getHhId()); + entity.setFormId(dto.getFormId()); + entity.setVersion(dto.getVersion()); + entity.setVisitNo(dto.getVisitNo()); + entity.setFollowUpNo(dto.getFollowUpNo()); + if (dto.getFollowUpDate() != null) { + entity.setFollowUpDate(dto.getFollowUpDate()); + + } + entity.setDiagnosisCodes(dto.getDiagnosisCodes()); + entity.setFormDataJson(dto.getFormDataJson()); + entity.setUserID(userId); + entity.setCreatedBy(userName); + entity.setUpdatedBy(userId); + + + if (dto.getTreatmentStartDate() != null) { + entity.setTreatmentStartDate( + LocalDate.parse(dto.getTreatmentStartDate()) + ); + } + + ChronicDiseaseVisitEntity savedEntity = + chronicDiseaseVisitRepository.save(entity); + + dto.setId(savedEntity.getId()); + responseList.add(dto); + checkIncentive(savedEntity, savedEntity.getUserID()); + + + } + + return responseList; + } + + private void checkIncentive(ChronicDiseaseVisitEntity chronicDiseaseVisitEntity, Integer ashaId) { + String userName = userRepo.getUserNamedByUserId(ashaId); + Integer stateId = userService.getUserDetail(ashaId).getStateId(); + IncentiveActivity incentiveActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_FOLLOWUP_TREATMENT", GroupName.NCD.getDisplayName()); + IncentiveActivity incentiveActivityCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_FOLLOWUP_TREATMENT", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity incentiveActivityCGForNCDnewPatient = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_NEW_PATIENT_MEDICATION_SUPPORT", GroupName.ACTIVITY.getDisplayName()); + logger.info("incentiveActivity:" + incentiveActivity.getId()); + + if (chronicDiseaseVisitEntity.getFollowUpNo() != null + && chronicDiseaseVisitEntity.getCreatedDate() != null + && chronicDiseaseVisitEntity.getDiagnosisCodes() != null) { + + List targetDiseases = Arrays.asList( + "Hypertension (BP)", + "Diabetes (DM)", + "Cancer" + ); + + + List diagnosisList = Arrays.asList( + chronicDiseaseVisitEntity.getDiagnosisCodes().split(",") + ); + + boolean matchFound = diagnosisList.stream() + .map(String::trim) + .anyMatch(targetDiseases::contains); + if(matchFound & Integer.valueOf(0).equals(chronicDiseaseVisitEntity.getFollowUpNo()) ){ + LocalDateTime localDateTime = chronicDiseaseVisitEntity.getTreatmentStartDate().atStartOfDay(); + + Timestamp treatmentStartDate = Timestamp.valueOf(localDateTime); + addNCDFolloupIncentiveRecord( + incentiveActivityCGForNCDnewPatient, + ashaId, + chronicDiseaseVisitEntity.getBenId(), + treatmentStartDate, + userName + ); } + if (matchFound && Integer.valueOf(6).equals(chronicDiseaseVisitEntity.getFollowUpNo())) { + LocalDateTime localDateTime = chronicDiseaseVisitEntity.getFollowUpDate().atStartOfDay(); + + Timestamp followUpTimestamp = Timestamp.valueOf(localDateTime); + if(stateId.equals(StateCode.AM.getStateCode())){ + addNCDFolloupIncentiveRecord( + incentiveActivity, + ashaId, + chronicDiseaseVisitEntity.getBenId(), + followUpTimestamp, + userName + ); + } + if(stateId.equals(StateCode.CG.getStateCode())){ + addNCDFolloupIncentiveRecord( + incentiveActivityCG, + ashaId, + chronicDiseaseVisitEntity.getBenId(), + followUpTimestamp, + userName + ); + } + } } + + + + } + + private void addNCDFolloupIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId, + Long benId, Timestamp createdDate, String userName) { + try { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), createdDate, benId,ashaId); + + Timestamp now = Timestamp.valueOf(LocalDateTime.now()); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(createdDate); + record.setCreatedBy(userName); + record.setStartDate(createdDate); + record.setEndDate(createdDate); + record.setUpdatedDate(now); + record.setUpdatedBy(userName); + record.setBenId(benId); + record.setAshaId(ashaId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + } + } catch (Exception e) { + logger.error("Fail to save IncentiveActivityRecord " + e.getMessage()); } + + + } + + @Override + public List getCdtfVisits(GetBenRequestHandler getBenRequestHandler) { + List dtoList = new ArrayList<>(); + + try { + + List entityList = chronicDiseaseVisitRepository.findByUserID(getBenRequestHandler.getAshaId()); + + + for (ChronicDiseaseVisitEntity entity : entityList) { + + ChronicDiseaseVisitDTO dto = new ChronicDiseaseVisitDTO(); + + dto.setId(entity.getId()); + dto.setBenId(entity.getBenId()); + dto.setHhId(entity.getHhId()); + dto.setFormId(entity.getFormId()); + dto.setVersion(entity.getVersion()); + dto.setVisitNo(entity.getVisitNo()); + dto.setFollowUpNo(entity.getFollowUpNo()); + if (entity.getFollowUpDate() != null) { + dto.setFollowUpDate(entity.getFollowUpDate()); + + } + dto.setDiagnosisCodes(entity.getDiagnosisCodes()); + dto.setFormDataJson(entity.getFormDataJson()); + + if (entity.getTreatmentStartDate() != null) { + dto.setTreatmentStartDate( + entity.getTreatmentStartDate().toString() + ); + } + checkIncentive(entity, entity.getUserID()); + dtoList.add(dto); + } + } catch (Exception e) { + + } + + return dtoList; } } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/EmployeeMasterImpl.java b/src/main/java/com/iemr/flw/service/impl/EmployeeMasterImpl.java index 2f67fc2b3..acf7836c5 100644 --- a/src/main/java/com/iemr/flw/service/impl/EmployeeMasterImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/EmployeeMasterImpl.java @@ -1,6 +1,6 @@ package com.iemr.flw.service.impl; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.repo.iemr.EmployeeMasterRepo; import com.iemr.flw.service.EmployeeMasterInter; @@ -19,13 +19,13 @@ public class EmployeeMasterImpl implements EmployeeMasterInter { @Override - public M_User getUserDetails(Integer userID) { + public User getUserDetails(Integer userID) { logger.debug("Fetching user details for userID: {}", userID); try { if (userID == null) { throw new IllegalArgumentException("UserID cannot be null"); } - return employeeMasterRepo.findByUserID(userID); + return employeeMasterRepo.findUserByUserID(userID); } catch (Exception e) { logger.error("Error fetching user details for userID: {}", userID, e); throw e; @@ -33,7 +33,7 @@ public M_User getUserDetails(Integer userID) { } @Override - public List getAllUsers() { + public List getAllUsers() { return employeeMasterRepo.findAll(); } } diff --git a/src/main/java/com/iemr/flw/service/impl/FacilityDataService.java b/src/main/java/com/iemr/flw/service/impl/FacilityDataService.java new file mode 100644 index 000000000..2e4f9556d --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/FacilityDataService.java @@ -0,0 +1,186 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.AshaSupervisorMapping; +import com.iemr.flw.repo.iemr.AshaSupervisorLoginRepo; +import com.iemr.flw.repo.iemr.FacilityLoginRepo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class FacilityDataService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired + private AshaSupervisorLoginRepo ashaSupervisorLoginRepo; + + @Autowired + private FacilityLoginRepo facilityLoginRepo; + + public Map buildFacilityData(Integer userID, String roleName) { + Map result = new HashMap<>(); + result.put("location", emptyLocation()); + try { + if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { + enrichAshaSupervisorData(result, userID); + } else if ("ASHA".equalsIgnoreCase(roleName)) { + enrichAshaData(result, userID); + } else { + enrichGeneralFacilityData(result, userID); + } + } catch (Exception e) { + logger.error("Error building facilityData for userID " + userID + ": " + e.getMessage(), e); + } + return result; + } + + private void enrichAshaSupervisorData(Map result, Integer supervisorUserID) { + ArrayList mappings = ashaSupervisorLoginRepo + .findBySupervisorUserIDAndDeletedFalse(supervisorUserID); + if (mappings == null || mappings.isEmpty()) return; + + Set facilityIDSet = new HashSet<>(); + for (AshaSupervisorMapping m : mappings) { + if (m.getFacilityID() != null) facilityIDSet.add(m.getFacilityID()); + } + if (facilityIDSet.isEmpty()) return; + List facilityIDs = new ArrayList<>(facilityIDSet); + + List facilityRows = facilityLoginRepo.getFacilityDetails(facilityIDs); + if (facilityRows == null || facilityRows.isEmpty()) return; + + result.put("location", buildLocation(facilityRows.get(0))); + + List> facilities = new ArrayList<>(); + for (Object[] row : facilityRows) { + Map facility = new HashMap<>(); + facility.put("facilityId", row[0]); + facility.put("facilityName", str(row[1])); + facility.put("facilityType", str(row[9])); + facilities.add(facility); + } + result.put("facilities", facilities); + + List ashaRows = facilityLoginRepo.getMappedAshasBySupervisor(supervisorUserID); + List> ashaList = buildAshaList(ashaRows); + result.put("ashaList", ashaList); + result.put("totalAshaCount", ashaList.size()); + } + + private void enrichAshaData(Map result, Integer ashaUserID) { + List facilityIDs = facilityLoginRepo.getUserFacilityIDs(ashaUserID); + if (facilityIDs == null || facilityIDs.isEmpty()) return; + + List facilityRows = facilityLoginRepo.getFacilityDetails(facilityIDs); + if (facilityRows == null || facilityRows.isEmpty()) return; + + result.put("location", buildLocation(facilityRows.get(0))); + + Object[] row = facilityRows.get(0); + Map facility = new HashMap<>(); + facility.put("facilityId", row[0]); + facility.put("facilityName", str(row[1])); + facility.put("facilityType", str(row[9])); + result.put("facility", facility); + + List supervisorRows = facilityLoginRepo.getSupervisorForAsha(ashaUserID); + if (supervisorRows != null && !supervisorRows.isEmpty()) { + Object[] sRow = supervisorRows.get(0); + Map supervisor = new HashMap<>(); + supervisor.put("userId", sRow[0]); + supervisor.put("fullName", fullName(sRow[1], sRow[2])); + supervisor.put("mobile", str(sRow[3])); + supervisor.put("employeeId", str(sRow[4]).isEmpty() ? null : str(sRow[4])); + result.put("supervisor", supervisor); + } else { + result.put("supervisor", null); + } + + List peerRows = facilityLoginRepo.getPeersAtFacility(facilityIDs, ashaUserID); + List> peers = new ArrayList<>(); + if (peerRows != null) { + for (Object[] pRow : peerRows) { + Map peer = new HashMap<>(); + peer.put("userId", pRow[0]); + peer.put("fullName", fullName(pRow[1], pRow[2])); + peer.put("role", str(pRow[3])); + peer.put("employeeId", str(pRow[4]).isEmpty() ? null : str(pRow[4])); + peer.put("mobile", str(pRow[5]).isEmpty() ? null : str(pRow[5])); + peers.add(peer); + } + } + result.put("peersAtFacility", peers); + } + + private void enrichGeneralFacilityData(Map result, Integer userID) { + List facilityIDs = facilityLoginRepo.getUserFacilityIDs(userID); + if (facilityIDs == null || facilityIDs.isEmpty()) return; + + List facilityRows = facilityLoginRepo.getFacilityDetails(facilityIDs); + if (facilityRows == null || facilityRows.isEmpty()) return; + + result.put("location", buildLocation(facilityRows.get(0))); + + List> facilities = new ArrayList<>(); + for (Object[] row : facilityRows) { + Map facility = new HashMap<>(); + facility.put("facilityId", row[0]); + facility.put("facilityName", str(row[1])); + facility.put("facilityType", str(row[9])); + facilities.add(facility); + } + result.put("facilities", facilities); + + List ashaRows = facilityLoginRepo.getAshaListByFacilities(facilityIDs); + List> ashaList = buildAshaList(ashaRows); + result.put("ashaList", ashaList); + result.put("totalAshaCount", ashaList.size()); + } + + private List> buildAshaList(List rows) { + List> list = new ArrayList<>(); + if (rows == null) return list; + for (Object[] row : rows) { + Map asha = new HashMap<>(); + asha.put("userId", row[0]); + asha.put("fullName", fullName(row[1], row[2])); + asha.put("employeeId", str(row[3]).isEmpty() ? null : str(row[3])); + asha.put("facilityId", row[4]); + asha.put("facilityName", str(row[5])); + asha.put("facilityType", str(row[6])); + asha.put("mobile", str(row[7]).isEmpty() ? null : str(row[7])); + list.add(asha); + } + return list; + } + + private Map buildLocation(Object[] facilityRow) { + Map location = new HashMap<>(); + location.put("state", str(facilityRow[3])); + location.put("district", str(facilityRow[5])); + location.put("blockOrUlb", str(facilityRow[7])); + location.put("locationType", str(facilityRow[8])); + return location; + } + + private Map emptyLocation() { + Map location = new HashMap<>(); + location.put("state", ""); + location.put("district", ""); + location.put("blockOrUlb", ""); + location.put("locationType", ""); + return location; + } + + private String str(Object val) { + return val != null ? val.toString() : ""; + } + + private String fullName(Object first, Object last) { + return (str(first) + " " + str(last)).trim(); + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java index e47712294..362dc1ea8 100644 --- a/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java @@ -1,6 +1,8 @@ package com.iemr.flw.service.impl; import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.controller.DeathReportsController; +import com.iemr.flw.domain.iemr.EligibleCoupleRegister; import com.iemr.flw.domain.iemr.IFAFormSubmissionData; import com.iemr.flw.domain.iemr.IncentiveActivity; import com.iemr.flw.domain.iemr.IncentiveActivityRecord; @@ -9,13 +11,15 @@ import com.iemr.flw.dto.iemr.IFAFormSubmissionRequest; import com.iemr.flw.dto.iemr.IFAFormSubmissionResponse; import com.iemr.flw.masterEnum.GroupName; -import com.iemr.flw.repo.iemr.IFAFormSubmissionRepository; -import com.iemr.flw.repo.iemr.IncentiveRecordRepo; -import com.iemr.flw.repo.iemr.IncentivesRepo; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import com.iemr.flw.masterEnum.StateCode; +import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.IFAFormSubmissionService; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; +import jakarta.persistence.criteria.CriteriaBuilder; import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -31,6 +35,9 @@ public class IFAFormSubmissionServiceImpl implements IFAFormSubmissionService { private final IFAFormSubmissionRepository repository; private final ObjectMapper mapper = new ObjectMapper(); + private final Logger logger = LoggerFactory.getLogger(IFAFormSubmissionServiceImpl.class); + + @Autowired private JwtUtil jwtUtil; @@ -42,8 +49,14 @@ public class IFAFormSubmissionServiceImpl implements IFAFormSubmissionService { @Autowired private IncentiveRecordRepo incentiveRecordRepo; + @Autowired + private UserService userService; + + @Autowired + private EligibleCoupleRegisterRepo eligibleCoupleRegisterRepo; + @Override - public String saveFormData(List requests) { + public String saveFormData(List requests, Integer userId) { try { List entities = new ArrayList<>(); for (IFAFormSubmissionRequest req : requests) { @@ -60,7 +73,7 @@ public String saveFormData(List requests) { entities.add(data); } repository.saveAll(entities); - checkIFAIncentive(entities); + checkIFAIncentive(entities,userId); return "Form data saved successfully"; } catch (Exception e) { e.printStackTrace(); @@ -68,16 +81,37 @@ public String saveFormData(List requests) { } } - private void checkIFAIncentive(List entities) { - IncentiveActivity incentiveActivityAM= incentivesRepo.findIncentiveMasterByNameAndGroup("NIPI_CHILDREN", GroupName.CHILD_HEALTH.getDisplayName()); - - if(incentiveActivityAM!=null){ - entities.forEach(ifaFormSubmissionData -> { - addIFAIncentive(ifaFormSubmissionData,incentiveActivityAM); + private void checkIFAIncentive(List entities,Integer userId) { + try { + List records = repository.findByUserId(userId); + List eligibleCoupleRegisters = eligibleCoupleRegisterRepo.getECRegRecords(userService.getUserDetail(userId).getUserName()); + int totalEligibleCouples = eligibleCoupleRegisters.size(); + int totalIFASubmissions = records.size(); + if(totalEligibleCouples>0){ + double percentage = + (totalIFASubmissions * 100.0) / totalEligibleCouples; + if(percentage>=70){ + Integer stateCode = userService.getUserDetail(userId).getStateId(); + if(stateCode.equals(StateCode.CG.getStateCode())){ + IncentiveActivity incentiveActivityCG= incentivesRepo.findIncentiveMasterByNameAndGroup("NATIONAL_IRON_PLUS", GroupName.ACTIVITY.getDisplayName()); + + if(incentiveActivityCG!=null){ + entities.forEach(ifaFormSubmissionData -> { + addIFAIncentive(ifaFormSubmissionData,incentiveActivityCG); + + }); + } + + } + } + } + }catch (Exception e){ + logger.error("Error while processing IFA incentive", e); - }); } + + } private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, IncentiveActivity incentiveActivityAM) { @@ -87,10 +121,10 @@ private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, Incent Timestamp ifaVisitDateTimestamp = Timestamp.valueOf(ifaVisitDate.atStartOfDay()); - IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivityAM.getId(),ifaVisitDateTimestamp,ifaFormSubmissionData.getBeneficiaryId()); + IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivityAM.getId(),ifaVisitDateTimestamp,ifaFormSubmissionData.getBeneficiaryId(),userServiceRoleRepo.getUserIdByName(ifaFormSubmissionData.getUserName())); if(incentiveActivityRecord==null){ incentiveActivityRecord = new IncentiveActivityRecord(); - incentiveActivityRecord.setActivityId(ifaFormSubmissionData.getId()); + incentiveActivityRecord.setActivityId(incentiveActivityAM.getId()); incentiveActivityRecord.setCreatedDate(ifaVisitDateTimestamp); incentiveActivityRecord.setStartDate(ifaVisitDateTimestamp); incentiveActivityRecord.setEndDate(ifaVisitDateTimestamp); @@ -100,6 +134,7 @@ private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, Incent incentiveActivityRecord.setBenId(ifaFormSubmissionData.getBeneficiaryId()); incentiveActivityRecord.setAshaId(userServiceRoleRepo.getUserIdByName(ifaFormSubmissionData.getUserName())); incentiveActivityRecord.setAmount(Long.valueOf(incentiveActivityAM.getRate())); + incentiveActivityRecord.setIsEligible(true); incentiveRecordRepo.save(incentiveActivityRecord); } } diff --git a/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java index b294a3dcb..26a5c1c74 100644 --- a/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java @@ -17,7 +17,7 @@ public class IRSRoundServiceImpl implements IRSRoundService { private IRSRoundRepo irsRoundRepository; @Override - public List addRounds(List dtos) { + public List addRounds(List dtos,Integer userId,String userName) { // Validate input DTOs for (IRSRoundDTO dto : dtos) { if (dto.getDate() == null || dto.getHouseholdId() == null) { @@ -26,7 +26,7 @@ public List addRounds(List dtos) { } return irsRoundRepository.saveAll( dtos.stream() - .map(dto -> new IRSRound(null, dto.getDate(), dto.getRounds(), dto.getHouseholdId())) + .map(dto -> new IRSRound(null, dto.getDate(), dto.getRounds(), dto.getHouseholdId(),userName,userId)) .collect(Collectors.toList()) ); } diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java new file mode 100644 index 000000000..b6e4b7c7a --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java @@ -0,0 +1,708 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.IncentiveActivity; +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; +import com.iemr.flw.repo.iemr.IncentiveRecordRepo; +import com.iemr.flw.repo.iemr.IncentivesRepo; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.util.Date; + +@Service +public class IncentiveLogicImpl implements IncentiveLogicService { + + private static final Logger logger = LoggerFactory.getLogger(IncentiveLogicImpl.class); + + @Autowired + private IncentivesRepo incentivesRepo; + + @Autowired + private IncentiveRecordRepo incentiveRecordRepo; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserService userService; + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; + + @Override + public IncentiveActivityRecord incentiveForLeprosyPaucibacillaryConfirmed( + Long benId, + Date treatmentStartDate, + Date treatmentEndDate, + Integer userId) { + + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NLEP_PB_TREATMENT"; + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check NLEP_PB_TREATMENT Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForTbSuspected(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "INFORMANT_INCENTIVE"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Tb Suspected Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForLeprosyMultibacillaryConfirmed( + Long benId, + Date treatmentStartDate, + Date treatmentEndDate, + Integer userId) { + + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NLEP_MB_TREATMENT"; + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check NLEP_MB_TREATMENT Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForVhndMeeting(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "VHND_PARTICIPATION"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check VHND_PARTICIPATION Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForClusterMeeting(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "CLUSTER_MEETING"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check CLUSTER_MEETING Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForAttendingVhsnc(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "VHSNC_MEETING"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check VHSNC_MEETING Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForChildBirthGap(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "FP_DELAY_2Y"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check FP_DELAY_2Y Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForEyeSurgeyReferGovtHospital(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NPCB_GOVT_CATARACT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Eye surgery Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForEyeSurgeyReferPrivateHospital(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NPCB_PRIVATE_CATARACT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Eye surgery Incentive Exception: ", e); + return null; + } + } + + + + @Override + public IncentiveActivityRecord incentiveForGiveingIFA(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NIPI_CHILDREN"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.CHILD_HEALTH.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check IFA Exception: ", e); + return null; + } } + + @Override + public IncentiveActivityRecord incentiveForTbFollowUpIsDrTb(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "DRTB_TREATMENT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check TB Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForTbFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "DSTB_TREATMENT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check TB Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForMalariaFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NVBDCP_MALARIA_TREATMENT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Eye surgery Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForSecondChildGap(Long benId, Timestamp secondChildDob, Timestamp secondChildDob1, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "1st_2nd_CHILD_GAP"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + secondChildDob, + secondChildDob1, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.FAMILY_PLANNING.getDisplayName(), + benId, + secondChildDob, + secondChildDob1, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check FP_DELAY_2Y Incentive Exception: ", e); + return null; + } + } + + + + @Override + public IncentiveActivityRecord incentiveForIdentificationLeprosy(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NLEP_CASE_DETECTION"; + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Leprosy Incentive Exception: ", e); + return null; + } + } + + private IncentiveActivityRecord processIncentive(String activityName, String groupName, Long benId, + Date startDate, Date endDate, Integer userId) { + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup(activityName, groupName); + + if (activity == null) { + logger.info("No IncentiveActivity found for name: {} and group: {}", activityName, groupName); + return null ; + } + + return saveIncentive(activity, benId, startDate, endDate, userId); + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + return null; + + } + } + + private IncentiveActivityRecord saveIncentive( + IncentiveActivity activity, + Long benId, + Date startDate, + Date endDate, + Integer userId) { + + try { + String userName = userServiceRoleRepo.getUserNamedByUserId(userId); + + if (activity == null || benId == null || startDate == null || endDate == null) { + logger.warn("Invalid input for saving incentive"); + return null; + } + + Timestamp startTimestamp = new Timestamp(startDate.getTime()); + Timestamp endTimestamp = new Timestamp(endDate.getTime()); + + + // 🔍 duplicate check + IncentiveActivityRecord existing = incentiveRecordRepo + .findRecordByActivityIdCreatedDateBenId( + activity.getId(), startTimestamp, benId,userId); + + if (existing != null) { + logger.info("Incentive already exists for benId: {}, activityId: {}", + benId, activity.getId()); + return existing; + } + + // 🆕 create record + IncentiveActivityRecord record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setStartDate(startTimestamp); + record.setEndDate(endTimestamp); + record.setCreatedBy(userName); + record.setUpdatedBy(userName); + record.setBenId(benId); + record.setAshaId(userId); + record.setAmount(Long.valueOf(activity.getRate())); + + record = incentiveRecordRepo.save(record); + + logger.info("Incentive saved successfully for benId: {}", benId); + + return record; + + } catch (Exception e) { + logger.error("Error Incentive Exception: ", e); + return null; + } + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 6a42b76d9..f109c88a8 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -1,239 +1,904 @@ package com.iemr.flw.service.impl; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.iemr.flw.domain.identity.RMNCHMBeneficiarydetail; -import com.iemr.flw.domain.iemr.IncentiveActivity; -import com.iemr.flw.domain.iemr.IncentiveActivityLangMapping; -import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.IncentiveApprovalStatus; +import com.iemr.flw.masterEnum.IncentiveName; import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; -import com.iemr.flw.repo.iemr.IncentiveActivityLangMappingRepo; -import com.iemr.flw.repo.iemr.IncentiveRecordRepo; -import com.iemr.flw.repo.iemr.IncentivesRepo; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.IncentiveService; +import com.iemr.flw.service.MaaMeetingService; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; +import jakarta.persistence.criteria.CriteriaBuilder; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import java.math.BigInteger; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import java.util.stream.Collectors; @Service public class IncentiveServiceImpl implements IncentiveService { - private final Logger logger = LoggerFactory.getLogger(ChildCareServiceImpl.class); + + private final Logger logger = LoggerFactory.getLogger(IncentiveServiceImpl.class); @Autowired private BeneficiaryRepo beneficiaryRepo; + @Autowired + private IncentiveActivityLangMappingRepo incentiveActivityLangMappingRepo; + @Autowired + private IncentivesRepo incentivesRepo; + @Autowired + private IncentiveRecordRepo recordRepo; + @Autowired + private IncentivePendingActivityRepository incentivePendingActivityRepository; + @Autowired + private UserServiceRoleRepo userRepo; + ; ModelMapper modelMapper = new ModelMapper(); @Autowired - private IncentiveActivityLangMappingRepo incentiveActivityLangMappingRepo; + private JwtUtil jwtUtil; + @Autowired - IncentivesRepo incentivesRepo; + private MaaMeetingService maaMeetingService; @Autowired - IncentiveRecordRepo recordRepo; + private BenReferDetailsRepo benReferDetailsRepo; @Autowired - private JwtUtil jwtUtil; + private CbacIemrDetailsRepo cbacIemrDetailsRepo; @Autowired - private UserServiceRoleRepo userRepo; + private UserService userService; + + @Autowired + private EligibleCoupleRegisterRepo eligibleCoupleRegisterRepo; + + @Autowired + private IFAFormSubmissionRepository ifaFormSubmissionRepository; + + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + + + // ================= MASTER SAVE ================= @Override public String saveIncentivesMaster(List activityDTOS) { try { - activityDTOS.forEach(activityDTO -> { + for (IncentiveActivityDTO dto : activityDTOS) { IncentiveActivity activity = - incentivesRepo.findIncentiveMasterByNameAndGroup(activityDTO.getName(), activityDTO.getGroup()); + incentivesRepo.findIncentiveMasterByNameAndGroup(dto.getName(), dto.getGroup()); if (activity == null) { activity = new IncentiveActivity(); - modelMapper.map(activityDTO, activity); - } else { - Long id = activity.getId(); - modelMapper.map(activityDTO, activity); - activity.setId(id); } + + modelMapper.map(dto, activity); incentivesRepo.save(activity); - }); - String saved = ""; - activityDTOS.forEach(dto -> saved.concat(dto.getGroup() + ": " + dto.getName())); - return "saved master data for " + saved ; + } + return "Saved successfully"; } catch (Exception e) { - + logger.error("Error saving incentives", e); + return "Error"; } - return null; } + // ================= GET MASTER ================= @Override public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { try { + Integer stateCode = incentiveRequestDTO.getState(); + String langCode = incentiveRequestDTO.getLangCode(); - List incs = new ArrayList<>(); - if(incentiveRequestDTO.getState()==StateCode.CG.getStateCode()){ - incs = incentivesRepo.findAll().stream().filter(incentiveActivity -> incentiveActivity.getGroup().equals("ACTIVITY")).collect(Collectors.toList()); + // Integer comparison using intValue() — safe and reliable + boolean isCG = stateCode != null && stateCode.intValue() == StateCode.CG.getStateCode(); + boolean isAM = stateCode != null && stateCode.intValue() == StateCode.AM.getStateCode(); - }else { - incs = incentivesRepo.findAll().stream().filter(incentiveActivity -> !incentiveActivity.getGroup().equals("ACTIVITY")).collect(Collectors.toList()); + // Single filtered DB query instead of findAll() + stream filter + List incs = isCG + ? incentivesRepo.findByGroupAndIsDeleted("ACTIVITY", false) + : incentivesRepo.findByGroupNotAndIsDeleted("ACTIVITY", false); + if (incs.isEmpty()) { + return new Gson().toJson(Collections.emptyList()); } - List dtos = incs.stream().map(inc -> { - IncentiveActivityDTO dto = modelMapper.map(inc, IncentiveActivityDTO.class); - // Fetch language mapping - IncentiveActivityLangMapping mapping = incentiveActivityLangMappingRepo - .findByIdAndName(inc.getId(),inc.getName()); + // Fetch ALL lang mappings in ONE query instead of N queries in loop + List ids = incs.stream() + .map(IncentiveActivity::getId) + .collect(Collectors.toList()); + Map mappingById = incentiveActivityLangMappingRepo + .findAllByIdIn(ids) + .stream() + .collect(Collectors.toMap( + IncentiveActivityLangMapping::getId, + Function.identity() + )); + List dtos = incs.stream().map(inc -> { + IncentiveActivityDTO dto = modelMapper.map(inc, IncentiveActivityDTO.class); + IncentiveActivityLangMapping mapping = mappingById.get(inc.getId()); if (mapping != null) { dto.setName(mapping.getName()); - dto.setGroupName(mapping.getGroup()); - if(Objects.equals(incentiveRequestDTO.getLangCode(), "en")){ + + if (isCG) { + dto.setGroupName(""); + } else if (isAM) { + dto.setGroupName(mapping.getGroup()); + } + + // Set description based on language + if ("as".equals(langCode)) { + dto.setDescription(mapping.getAssameActivityDescription() != null + ? mapping.getAssameActivityDescription() + : mapping.getDescription()); + + } else if ("hi".equals(langCode)) { + dto.setDescription(mapping.getHindiActivityDescription() != null + ? mapping.getHindiActivityDescription() + : mapping.getDescription()); + + } else { + // default "en" dto.setDescription(inc.getDescription()); + } + + } else { + if (isCG) { + dto.setGroupName(""); + } else { + dto.setGroupName(inc.getGroup()); + } + } - }else if(Objects.equals(incentiveRequestDTO.getLangCode(), "as")){ + return dto; + }).collect(Collectors.toList()); - if(mapping.getAssameActivityDescription()!=null){ - dto.setDescription(mapping.getAssameActivityDescription()); + Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return gson.toJson(dtos); - }else { - dto.setDescription(mapping.getDescription()); + } catch (Exception e) { + logger.error("Error in getIncentiveMaster: ", e); + } + return null; + } - } + @Override + public String getAllIncentivesByUserId(GetBenRequestHandler request) { + int page = 0; + int size = 20; + Page pageResult; + List finalDtos = new ArrayList<>(); + + Integer stateCode = userService.getUserDetail(request.getAshaId()).getStateId(); + String userName = userService.getUserDetail(request.getAshaId()).getUserName(); + try { + + if (stateCode.equals(StateCode.AM.getStateCode())) { + checkMonthlyAshaIncentive(request.getAshaId()); + } + if (stateCode.equals(StateCode.CG.getStateCode())) { + checkMonthlyAshaIncentiveForCg(request.getAshaId()); + + } + + } catch (Exception e) { + logger.error("Error in checkMonthlyAshaIncentive: ", e); + } + + try { + addIncentiveForIronTablets(request.getAshaId()); + incentiveOfNcdReferal(request.getAshaId(), request.getVillageID()); + + } catch (Exception e) { + logger.error("Error in incentiveOfNcdReferal: ", e); + } + + boolean isCG = stateCode != null && stateCode.equals(StateCode.CG.getStateCode()); + + do { + + Pageable pageable = PageRequest.of( + page, + size, + Sort.by("id").descending() // latest first + ); + + pageResult = recordRepo.findRecordsByAsha( + request.getAshaId(), + pageable + ); + + List entities = pageResult.getContent(); + + if (entities.isEmpty()) { + return new Gson().toJson(Collections.emptyList()); + } - }else if(Objects.equals(incentiveRequestDTO.getLangCode(), "hi")){ - if(mapping.getHindiActivityDescription()!=null){ - dto.setDescription(mapping.getHindiActivityDescription()); + // Step 2: Collect all activityIds — fetch valid ones in ONE query + List activityIds = entities.stream() + .map(IncentiveActivityRecord::getActivityId) + .distinct() + .collect(Collectors.toList()); + + // Single bulk query instead of N individual findIncentiveMasterById() calls + Set validActivityIds = isCG + ? incentivesRepo.findValidActivityIds(activityIds, true) + : incentivesRepo.findValidActivityIds(activityIds, false); + + // Filter entities based on valid activity IDs + entities = entities.stream() + .filter(e -> validActivityIds.contains(e.getActivityId())) + .collect(Collectors.toList()); + + // Step 3: Collect all benIds that need name lookup (name == null and benId > 0) + List benIdsToFetch = entities.stream() + .filter(e -> e.getName() == null && e.getBenId() != null && e.getBenId() > 0) + .map(IncentiveActivityRecord::getBenId) + .distinct() + .collect(Collectors.toList()); + + // Step 4: Bulk fetch all beneficiary names in ONE query instead of 3 queries per record + Map benIdToNameMap = new HashMap<>(); + if (!benIdsToFetch.isEmpty()) { + List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); + for (Object[] row : benDetails) { + Long benId = ((Number) row[0]).longValue(); + String first = row[1] != null ? (String) row[1] : ""; + String last = row[2] != null ? (String) row[2] : ""; + benIdToNameMap.put(benId, (first + " " + last).trim()); + } + } + + // Step 5: Map entities to DTOs + List dtos = entities.stream().map(entry -> { + if (entry.getName() == null) { + if (entry.getBenId() != null && entry.getBenId() > 0) { + String name = benIdToNameMap.getOrDefault(entry.getBenId(), ""); + entry.setName(name); + if (isCG) { + entry.setIsEligible(true); + } + } else { + entry.setName(""); + } + if (entry.getVerifiedByUserId() != null) { + entry.setSupervisorRole(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getRoleName()); + entry.setVerifiedByUserName(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getName()); - }else { - dto.setDescription(mapping.getDescription()); + } + if (entry.getAshaId() != null) { + if (entry.getCreatedBy() == null) { + entry.setCreatedBy(userName); + } + if (entry.getUpdatedBy() == null) { + entry.setUpdatedBy(userName); } + if (entry.getIsEligible() == null) { + entry.setIsEligible(true); + } } - }else { - dto.setGroupName(inc.getGroup()); } + return modelMapper.map(entry, IncentiveRecordDTO.class); + }).collect(Collectors.toList()); + finalDtos.addAll(dtos); + + page++; + + } while (pageResult.hasNext()); + + + + Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return gson.toJson(finalDtos); + } + + // ================= GROUPED SUMMARY ================= + @Override + public String getAllIncentivesGroupedSummary(GetBenRequestHandler request) { + + LocalDate start = LocalDate.of(request.getYear(), request.getMonth(), 1); + LocalDate end = start.withDayOfMonth(start.lengthOfMonth()); + + Timestamp startTs = Timestamp.valueOf(start.atStartOfDay()); + Timestamp endTs = Timestamp.valueOf(end.atTime(23, 59, 59)); + + Integer villageID = userRepo.getUserRole(request.getUserId()).get(0).getStateId(); + boolean isCG = villageID != null && villageID.intValue() == StateCode.CG.getStateCode(); + + List records = + recordRepo.findRecordsByAsha(request.getUserId()) + .stream() + .filter(r -> r.getCreatedDate() != null + && r.getEndDate() != null + && r.getEndDate().toLocalDateTime().getMonthValue() == request.getMonth() + && r.getEndDate().toLocalDateTime().getYear() == request.getYear() + && r.getIsClaimed()) + .toList(); + + + // Bulk fetch valid activity IDs — state wise + List activityIds = records.stream() + .map(IncentiveActivityRecord::getActivityId) + .collect(Collectors.toList()); + + Set validActivityIds = isCG + ? incentivesRepo.findValidActivityIds(activityIds, true) + : incentivesRepo.findValidActivityIds(activityIds, false); + + // Filter records based on valid activity IDs + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .collect(Collectors.toList()); + + Map> grouped = + records.stream().collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); + + List> result = new ArrayList<>(); + + for (var entry : grouped.entrySet()) { + + Long activityId = entry.getKey(); + List list = entry.getValue(); + + IncentiveActivity activity = + incentivesRepo.findById(activityId).orElse(null); + + if (activity == null) continue; + + long total = list.stream() + .mapToLong(r -> r.getAmount() != null ? r.getAmount() : 0) + .sum(); + + Map map = new HashMap<>(); + map.put("activityId", activityId); + map.put("activityDec", activity.getDescription()); + map.put("groupName", activity.getGroup()); + map.put("claimCount", list.size()); + map.put("totalAmount", total); + map.put("amount", activity.getRate()); + + result.add(map); + } + + return new Gson().toJson(result); + } + + @Override + public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { + try { + + LocalDate startDate = LocalDate.of(request.getYear(), request.getMonth(), 1); + LocalDate endDate = startDate.plusMonths(1); + + Timestamp startTs = Timestamp.valueOf(startDate.atStartOfDay()); + Timestamp endTs = Timestamp.valueOf(endDate.atStartOfDay()); + + List records = + recordRepo.findRecordsByAsha(request.getUserId()) + .stream() + .filter(r -> r.getActivityId() != null + && r.getActivityId().equals(request.getActivityId()) + && r.getCreatedDate() != null + && !r.getCreatedDate().before(startTs) + && r.getCreatedDate().before(endTs)) + .collect(Collectors.toList()); + + if (records.isEmpty()) { + return new Gson().toJson(new ArrayList<>()); + } + + // 🔹 Get beneficiary names + Set benIds = records.stream() + .map(IncentiveActivityRecord::getBenId) + .filter(id -> id != null && id > 0) + .collect(Collectors.toSet()); + + Map nameMap = new HashMap<>(); + + if (!benIds.isEmpty()) { + List data = beneficiaryRepo.findBenNamesByBenIds(new ArrayList<>(benIds)); + for (Object[] row : data) { + Long id = ((Number) row[0]).longValue(); + String name = (row[1] != null ? row[1] : "") + " " + + (row[2] != null ? row[2] : ""); + nameMap.put(id, name.trim()); + } + } + + // 🔹 Activity details + IncentiveActivity activity = + incentivesRepo.findById(request.getActivityId()).orElse(null); + + String groupName = activity != null ? activity.getGroup() : ""; + String description = activity != null ? activity.getDescription() : ""; + + // 🔹 Map result + List dtos = records.stream().map(r -> { + + if (r.getName() == null) { + if (r.getBenId() != null && r.getBenId() > 0) { + r.setName(nameMap.getOrDefault(r.getBenId(), "")); + } else { + r.setName(""); + } + } + + r.setGroupName(groupName); + r.setActivityDec(description); + + return modelMapper.map(r, IncentiveRecordDTO.class); - return dto; }).collect(Collectors.toList()); - Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return new GsonBuilder() + .setDateFormat("MMM dd, yyyy h:mm:ss a") + .create() + .toJson(dtos); - return gson.toJson(dtos); } catch (Exception e) { - e.printStackTrace(); + logger.error("Error in getAllIncentivesGroupedActivity", e); + return null; } - return null; - } @Override - public String getAllIncentivesByUserId(GetBenRequestHandler request) { + public String updateIncentive(PendingActivityDTO pendingActivityDTO) { + try { + + if (pendingActivityDTO == null) { + return "Invalid request"; + } + +// Optional optional = +// incentivePendingActivityRepository +// .findByUserIdAndModuleNameAndActivityId( +// pendingActivityDTO.getUserId(), +// pendingActivityDTO.getModuleName(), +// pendingActivityDTO.getId() +// ); +// +// if (!optional.isPresent()) { +// return "Record not found"; +// } + +// IncentivePendingActivity existing = optional.get(); + + if (pendingActivityDTO.getImages() == null || + pendingActivityDTO.getImages().isEmpty()) { + return "No images provided"; + } + + String module = pendingActivityDTO.getModuleName(); + + // 🔹 MAA MEETING + if ("MAA_MEETING".equalsIgnoreCase(module)) { + MaaMeetingRequestDTO dto = new MaaMeetingRequestDTO(); + dto.setMeetingImages( + pendingActivityDTO.getImages().toArray(new MultipartFile[0]) + ); + + //maaMeetingService.updateMeeting(dto); + return "Updated successfully"; + } + + // 🔹 HBNC + if ("HBNC".equalsIgnoreCase(module)) { +// childCareService.updateHbncFromFileUpload( +// pendingActivityDTO.getImages().toArray(new MultipartFile[0]), +// pendingActivityDTO.getId(), +// existing.getRecordId() +// ); + return "Updated successfully"; + } + + // 🔹 UWIN SESSION + if ("UWIN".equalsIgnoreCase(module)) { + UwinSessionRequestDTO dto = new UwinSessionRequestDTO(); + dto.setAttachments( + pendingActivityDTO.getImages().toArray(new MultipartFile[0]) + ); + +// uwinSessionService.updateSession( +// dto, +// existing.getRecordId(), +// pendingActivityDTO.getId() +// ); + + return "Updated successfully"; + } + + return "No matching module found"; - if(request.getVillageID()!= StateCode.CG.getStateCode()){ - checkMonthlyAshaIncentive(request.getAshaId()); + } catch (Exception e) { + logger.error("Error in updateIncentive", e); + return "Error: " + e.getMessage(); } + } + + + // ================= UPDATE CLAIM ================= + @Transactional + public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boolean isClaimed, String token) { + try { + LocalDate start = LocalDate.of(year, month, 1); + LocalDate end = start.plusMonths(1); - List dtos = new ArrayList<>(); - List entities = recordRepo.findRecordsByAsha(request.getAshaId()); - if(request.getVillageID()==StateCode.CG.getStateCode()){ - entities = entities.stream().filter(entitie-> incentivesRepo.findIncentiveMasterById(entitie.getActivityId(),true)!=null).collect(Collectors.toList()); + int updated = recordRepo.updateClaimStatusByAshaAndDateRange( + ashaId, + isClaimed, + Timestamp.valueOf(LocalDateTime.now()), + Timestamp.valueOf(start.atStartOfDay()), + Timestamp.valueOf(end.atStartOfDay()) + ); - }else { - entities = entities.stream().filter(entitie-> incentivesRepo.findIncentiveMasterById(entitie.getActivityId(),false)!=null).collect(Collectors.toList()); + return updated > 0 ? "Success" : "No records"; + } catch (Exception e) { + logger.error("Error", e); + return "Error"; } - entities.forEach(entry -> { - if(entry.getName()==null){ - if(entry.getBenId()!=0 && entry.getBenId()>0L){ - Long regId = beneficiaryRepo.getBenRegIdFromBenId(entry.getBenId()); - logger.info("rmnchBeneficiaryDetailsRmnch"+regId); - BigInteger benDetailId = beneficiaryRepo.findByBenRegIdFromMapping(BigInteger.valueOf(regId)).getBenDetailsId(); - RMNCHMBeneficiarydetail rmnchBeneficiaryDetails = beneficiaryRepo.findByBeneficiaryDetailsId(benDetailId); - String beneName = rmnchBeneficiaryDetails.getFirstName()+" "+rmnchBeneficiaryDetails.getLastName(); - entry.setName(beneName); + } - }else{ - entry.setName(""); + private void incentiveOfNcdReferal(Integer ashaId, Integer stateId) { + try { + String userName = userRepo.getUserNamedByUserId(ashaId); + String groupName = resolveGroupName(stateId); + Map activityMap = + incentivesRepo.findIncentiveMasterByNameAndGroup( + List.of("NCD_POP_ENUMERATION", "HWC_REFERRAL_10_CASES"), groupName + ).stream().collect(Collectors.toMap(IncentiveActivity::getName, Function.identity())); + + IncentiveActivity ncdPopEnumeration = activityMap.get("NCD_POP_ENUMERATION"); + + IncentiveActivity hwcReferralEnumeration = activityMap.get("HWC_REFERRAL_10_CASES"); + + CompletableFuture> benReferFuture = + CompletableFuture.supplyAsync(() -> benReferDetailsRepo.findByCreatedBy(userName)); + CompletableFuture> cbacFuture = + CompletableFuture.supplyAsync(() -> cbacIemrDetailsRepo.findByCreatedBy(userName)); + + List cbacDetailsImer = cbacFuture.get(); + + List recordsToSave = new ArrayList<>(); + + + if (ncdPopEnumeration != null && !cbacDetailsImer.isEmpty()) { + + final IncentiveActivity activity = ncdPopEnumeration; + cbacDetailsImer.forEach(cbacDetailsImer1 -> { + if(cbacDetailsImer1!=null){ + addNCDandCBACIncentiveRecord(activity, ashaId, cbacDetailsImer1.getBeneficiaryRegId(), cbacDetailsImer1.getCreatedDate(), userName); + } + }); + } + + if (hwcReferralEnumeration != null) { + logger.info("hwcReferralEnumeration :" + hwcReferralEnumeration.getDescription()); + logger.info("userName={}", userName); + + LocalDate now = LocalDate.now(); + + Long referralCount = benReferDetailsRepo.countMonthlyReferrals( + userName, + now.getMonthValue(), + now.getYear()); + + logger.info("referralCount :" + referralCount); + + + if (referralCount >= 10) { + + addHwcReferalAshaIncentiveRecord( + hwcReferralEnumeration, + ashaId, + userName + ); } + } + // ---- Single batch insert instead of N individual saves ---- + if (!recordsToSave.isEmpty()) { + recordRepo.saveAll(recordsToSave); } - dtos.add(modelMapper.map(entry, IncentiveRecordDTO.class)); + } catch (Exception e) { + logger.error("Error in incentiveOfNcdReferal for ashaId={}, stateId={}", ashaId, stateId, e); + } + } + + // Helper — record banana + private void addNCDandCBACIncentiveRecord(IncentiveActivity activity, Integer ashaId, + Long benId, Timestamp createdDate, String userName) { + + String lockKey = activity.getId() + "_" + benId + "_" + createdDate; + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + synchronized (lock){ + IncentiveActivityRecord incentiveActivityRecord = recordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId,ashaId); + if(incentiveActivityRecord==null){ + Timestamp now = Timestamp.valueOf(LocalDateTime.now()); + IncentiveActivityRecord record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(createdDate); + record.setCreatedBy(userName); + record.setStartDate(createdDate); + record.setEndDate(createdDate); + record.setUpdatedDate(now); + record.setUpdatedBy(userName); + record.setBenId(benId); + record.setAshaId(ashaId); + record.setAmount(Long.valueOf(activity.getRate())); + recordRepo.save(record); + } + lockMap.remove(lockKey, lock); + + } - }); - Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); - return gson.toJson(dtos); } - private void checkMonthlyAshaIncentive(Integer ashaId){ - IncentiveActivity MOBILEBILLREIMB_ACTIVITY = incentivesRepo.findIncentiveMasterByNameAndGroup("MOBILE_BILL_REIMB", GroupName.OTHER_INCENTIVES.getDisplayName()); - IncentiveActivity ADDITIONAL_ASHA_INCENTIVE = incentivesRepo.findIncentiveMasterByNameAndGroup("ADDITIONAL_ASHA_INCENTIVE", GroupName.ADDITIONAL_INCENTIVE.getDisplayName()); - IncentiveActivity ASHA_MONTHLY_ROUTINE = incentivesRepo.findIncentiveMasterByNameAndGroup("ASHA_MONTHLY_ROUTINE", GroupName.ASHA_MONTHLY_ROUTINE.getDisplayName()); - if(MOBILEBILLREIMB_ACTIVITY!=null){ - addMonthlyAshaIncentiveRecord(MOBILEBILLREIMB_ACTIVITY,ashaId); + + private String resolveGroupName(Integer stateId) { + if (stateId.equals(StateCode.CG.getStateCode())) { + logger.info("State id: {}", StateCode.CG.getStateCode()); + return GroupName.ACTIVITY.getDisplayName(); } - if(ADDITIONAL_ASHA_INCENTIVE!=null){ - addMonthlyAshaIncentiveRecord(ADDITIONAL_ASHA_INCENTIVE,ashaId); + logger.info("State id: {}", stateId); + return GroupName.NCD.getDisplayName(); + } + + private void checkMonthlyAshaIncentive(Integer ashaId) { + + try { + String userName = userRepo.getUserNamedByUserId(ashaId); + + IncentiveActivity MOBILEBILLREIMB_ACTIVITY = incentivesRepo.findIncentiveMasterByNameAndGroup("MOBILE_BILL_REIMB", GroupName.OTHER_INCENTIVES.getDisplayName()); + IncentiveActivity ADDITIONAL_ASHA_INCENTIVE = incentivesRepo.findIncentiveMasterByNameAndGroup("ADDITIONAL_ASHA_INCENTIVE", GroupName.ADDITIONAL_INCENTIVE.getDisplayName()); + IncentiveActivity ASHA_MONTHLY_ROUTINE = incentivesRepo.findIncentiveMasterByNameAndGroup("ASHA_MONTHLY_ROUTINE", GroupName.ASHA_MONTHLY_ROUTINE.getDisplayName()); + if (MOBILEBILLREIMB_ACTIVITY != null) { + addMonthlyAshaIncentiveRecord(MOBILEBILLREIMB_ACTIVITY, ashaId, userName); + } + if (ADDITIONAL_ASHA_INCENTIVE != null) { + addMonthlyAshaIncentiveRecord(ADDITIONAL_ASHA_INCENTIVE, ashaId, userName); + + } + + if (ASHA_MONTHLY_ROUTINE != null) { + addMonthlyAshaIncentiveRecord(ASHA_MONTHLY_ROUTINE, ashaId, userName); + + } + } catch (Exception e) { + logger.error("Error in addMonthlyAshaIncentiveRecord", e); } - if(ASHA_MONTHLY_ROUTINE!=null){ - addMonthlyAshaIncentiveRecord(ASHA_MONTHLY_ROUTINE,ashaId); + } + + private void checkMonthlyAshaIncentiveForCg(Integer ashaId) { + try { + String userName = userRepo.getUserNamedByUserId(ashaId); + + IncentiveActivity MONTHLY_HONORARIUM = incentivesRepo.findIncentiveMasterByNameAndGroup("MONTHLY_HONORARIUM", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity MITANIN_REGISTER_5_INFO_FILL = incentivesRepo.findIncentiveMasterByNameAndGroup("MITANIN_REGISTER_5_INFO_FILL", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity MITANIN_REGISTER = incentivesRepo.findIncentiveMasterByNameAndGroup("MITANIN_REGISTER", GroupName.ACTIVITY.getDisplayName()); + if (MONTHLY_HONORARIUM != null) { + addMonthlyAshaIncentiveRecord(MONTHLY_HONORARIUM, ashaId, userName); + } + if (MITANIN_REGISTER_5_INFO_FILL != null) { + addMonthlyAshaIncentiveRecord(MITANIN_REGISTER_5_INFO_FILL, ashaId, userName); + + } + + if (MITANIN_REGISTER != null) { + addMonthlyAshaIncentiveRecord(MITANIN_REGISTER, ashaId, userName); + + } + } catch (Exception e) { + logger.error("Error in addMonthlyAshaIncentiveRecord", e); } + } - private void addMonthlyAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId){ - Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + private void addMonthlyAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId, String userName) { + try { + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + + Timestamp startOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(1).atStartOfDay()); + Timestamp endOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).atTime(23, 59, 59)); + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + 0L, + ashaId, + startOfMonth, + endOfMonth + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(timestamp); + record.setCreatedBy(userName); + record.setStartDate(timestamp); + record.setEndDate(timestamp); + record.setUpdatedDate(timestamp); + record.setUpdatedBy(userName); + record.setBenId(0L); + record.setAshaId(ashaId); + record.setIsEligible(true); + record.setIsDefaultActivity(true); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } catch (Exception e) { + logger.error("Error in addMonthlyAshaIncentiveRecord", e); + + } + + } + + private void addHwcReferalAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId, String userName) { + try { + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + + Timestamp startOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(1).atStartOfDay()); + Timestamp endOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).atTime(23, 59, 59)); + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + 0L, + ashaId, + startOfMonth, + endOfMonth + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(timestamp); + record.setCreatedBy(userName); + record.setStartDate(timestamp); + record.setEndDate(timestamp); + record.setUpdatedDate(timestamp); + record.setUpdatedBy(userName); + record.setBenId(0L); + record.setAshaId(ashaId); + record.setIsEligible(true); + record.setIsDefaultActivity(false); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } catch (Exception e) { + logger.error("Error in addMonthlyAshaIncentiveRecord", e); + + } + + } + + private void addIncentiveForIronTablets(Integer userId) { + IncentiveActivity incentiveActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("NATIONAL_IRON_PLUS", GroupName.CHILD_HEALTH.getDisplayName()); + IncentiveActivity incentiveActivityCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NATIONAL_IRON_PLUS", GroupName.ACTIVITY.getDisplayName()); + + String userName = userService.getUserDetail(userId).getUserName(); + Integer stateId = userService.getUserDetail(userId).getStateId(); + if (userName != null) { + List eligibleCoupleRegisters = eligibleCoupleRegisterRepo.findByCreatedBy(userName); + List ifaFormSubmissionData = ifaFormSubmissionRepository.findByUserId(userId); + logger.info("eligibleCoupleRegisters :" + eligibleCoupleRegisters.size()); + logger.info("ifaFormSubmissionData :" + ifaFormSubmissionData.size()); + + if (!eligibleCoupleRegisters.isEmpty() && !ifaFormSubmissionData.isEmpty()) { + int percentage = (int) (((double) ifaFormSubmissionData.size() + / eligibleCoupleRegisters.size()) * 100); + + logger.info("IFA Count : {}", ifaFormSubmissionData.size()); + logger.info("Eligible Couple Count : {}", eligibleCoupleRegisters.size()); + logger.info("Percentage : {}", percentage); + + if (percentage >= 50) { + + if (stateId.equals(StateCode.AM.getStateCode())) { + addIFAIncentive( + ifaFormSubmissionData.get(ifaFormSubmissionData.size() - 1), + incentiveActivityAM, + userId, + userName); + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + addIFAIncentive( + ifaFormSubmissionData.get(ifaFormSubmissionData.size() - 1), + incentiveActivityCG, + userId, + userName); + } + } + } + + } + + + } + + private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, IncentiveActivity incentiveActivityAM, Integer userId, String userName) { Timestamp startOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(1).atStartOfDay()); Timestamp endOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).atTime(23, 59, 59)); - IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( - incentiveActivity.getId(), - startOfMonth, - endOfMonth, - 0L, - ashaId - ); - - - if (record == null) { - record = new IncentiveActivityRecord(); - record.setActivityId(incentiveActivity.getId()); - record.setCreatedDate(timestamp); - record.setCreatedBy(userRepo.getUserNamedByUserId(ashaId)); - record.setStartDate(timestamp); - record.setEndDate(timestamp); - record.setUpdatedDate(timestamp); - record.setUpdatedBy(userRepo.getUserNamedByUserId(ashaId)); - record.setBenId(0L); - record.setAshaId(ashaId); - record.setAmount(Long.valueOf(incentiveActivity.getRate())); - recordRepo.save(record); + String lockKey = incentiveActivityAM.getId() + "_" + 0 + "_" + startOfMonth; + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + + + logger.info("IFA incentive"); + synchronized (lock){ + IncentiveActivityRecord incentiveActivityRecord = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivityAM.getId(), + 0L, + userId, + startOfMonth, + endOfMonth + ); + if (incentiveActivityRecord == null) { + incentiveActivityRecord = new IncentiveActivityRecord(); + incentiveActivityRecord.setActivityId(incentiveActivityAM.getId()); + incentiveActivityRecord.setCreatedDate(timestamp); + incentiveActivityRecord.setStartDate(timestamp); + incentiveActivityRecord.setEndDate(timestamp); + incentiveActivityRecord.setUpdatedDate(timestamp); + incentiveActivityRecord.setUpdatedBy(ifaFormSubmissionData.getUserName()); + incentiveActivityRecord.setCreatedBy(ifaFormSubmissionData.getUserName()); + incentiveActivityRecord.setBenId(0L); + incentiveActivityRecord.setAshaId(userId); + incentiveActivityRecord.setAmount(Long.valueOf(incentiveActivityAM.getRate())); + recordRepo.save(incentiveActivityRecord); + logger.info("saved IFA incentive"); + + } + } + lockMap.remove(lockKey, lock); + + } diff --git a/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java index 03af282a7..bd0409903 100644 --- a/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java @@ -98,7 +98,7 @@ private void checkAndGenerateIncentive(List infantList) { } private void addIsSncuIncentive(IncentiveActivity activity, Long benId, String createdBy, Timestamp createdDate) { - IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId); + IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId,userServiceRoleRepo.getUserIdByName(createdBy)); if(incentiveActivityRecord==null){ incentiveActivityRecord = new IncentiveActivityRecord(); diff --git a/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java index 175c3666e..f5ef4a092 100644 --- a/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java @@ -1,14 +1,22 @@ package com.iemr.flw.service.impl; +import com.iemr.flw.controller.CoupleController; import com.iemr.flw.domain.iemr.MalariaFollowUp; import com.iemr.flw.dto.iemr.MalariaFollowListUpDTO; import com.iemr.flw.dto.iemr.MalariaFollowUpDTO; import com.iemr.flw.repo.iemr.MalariaFollowUpRepository; +import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.MalariaFollowUpService; +import com.iemr.flw.utils.JwtUtil; +import io.jsonwebtoken.Jwt; +import org.checkerframework.checker.units.qual.A; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.sql.Timestamp; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -19,30 +27,48 @@ public class MalariaFollowUpServiceImpl implements MalariaFollowUpService { @Autowired private MalariaFollowUpRepository repository; - public Boolean saveFollowUp(MalariaFollowUpDTO malariaFollowUpDTO) { + @Autowired + private IncentiveLogicService incentiveLogicService; + + private final Logger logger = LoggerFactory.getLogger(MalariaFollowUpServiceImpl.class); + + @Autowired + private JwtUtil jwtUtil; + + public Boolean saveFollowUp(MalariaFollowUpDTO malariaFollowUpDTO,String token) { + try { + for(MalariaFollowListUpDTO dto : malariaFollowUpDTO.getMalariaFollowListUp()){ + if (dto.getTreatmentStartDate().after(new Date())) { + return false; + } - for(MalariaFollowListUpDTO dto : malariaFollowUpDTO.getMalariaFollowListUp()){ - if (dto.getTreatmentStartDate().after(new Date())) { - return false; - } + if (dto.getTreatmentCompletionDate() != null && + dto.getTreatmentCompletionDate().before(dto.getTreatmentStartDate())) { + return false; + } - if (dto.getTreatmentCompletionDate() != null && - dto.getTreatmentCompletionDate().before(dto.getTreatmentStartDate())) { - return false; - } - if (dto.getReferralDate() != null && - dto.getReferralDate().before(dto.getTreatmentStartDate())) { - return false; - } + dto.setUserId(jwtUtil.extractUserId(token)); + MalariaFollowUp entity = new MalariaFollowUp(); + BeanUtils.copyProperties(dto, entity); + repository.save(entity); + if(entity!=null){ + incentiveLogicService.incentiveForMalariaFollowUp( + entity.getBenId(), + new Timestamp(entity.getTreatmentStartDate().getTime()), + new Timestamp(entity.getTreatmentCompletionDate().getTime()), + entity.getUserId() + ); + } + return true; + } + }catch (Exception e){ + logger.error("Exception saveFollowUp: "+ e.getMessage()); + return false; + } - MalariaFollowUp entity = new MalariaFollowUp(); - BeanUtils.copyProperties(dto, entity); - repository.save(entity); - return true; - } return false; } diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 53ba1d28d..41849ee3c 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -5,19 +5,31 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.IncentiveService; import com.iemr.flw.service.MaternalHealthService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; +import jakarta.transaction.Transactional; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Service @@ -58,6 +70,12 @@ public class MaternalHealthServiceImpl implements MaternalHealthService { @Autowired private IncentiveRecordRepo recordRepo; + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private IncentiveLogicService incentiveLogicService; + ObjectMapper mapper = new ObjectMapper(); @@ -67,10 +85,16 @@ public class MaternalHealthServiceImpl implements MaternalHealthService { @Autowired private SMSServiceImpl smsServiceImpl; + @Autowired + private AncCounsellingCareRepo ancCounsellingCareRepo; + public static final List PNC_PERIODS = Arrays.asList("1st Day", "3rd Day", "7th Day", "14th Day", "21st Day", "28th Day", "42nd Day"); + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + + @Override public String registerPregnantWoman(List pregnantWomanDTOs) { @@ -122,39 +146,68 @@ public List getANCVisits(GetBenRequestHandler dto) { try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); List ancVisits = ancVisitRepo.getANCForPW(user, dto.getFromDate(), dto.getToDate()); + checkAndAddIncentives(ancVisits, dto.getAshaId()); + return ancVisits.stream() .map(anc -> mapper.convertValue(anc, ANCVisitDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { - logger.error(e.getMessage()); + logger.error("ANC VISIT :---------------------" + e.getMessage()); } return null; } @Override - public String saveANCVisit(List ancVisitDTOs) { + public String saveANCVisit(List ancVisitDTOs, Integer userId) { try { + + logger.info("ANC save process started. Total records: {}", ancVisitDTOs.size()); + List ancList = new ArrayList<>(); List ancCareList = new ArrayList<>(); + ancVisitDTOs.forEach(it -> { - ANCVisit ancVisit = + + logger.info("Processing Beneficiary Id: {} ANC Visit: {}", it.getBenId(), it.getAncVisit()); + logger.info("Processing Beneficiary Id: {} ANC Visit: {}", it.getBenId(), it.getIsPaiucdId()); + + List ancVisitList = ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(it.getBenId(), it.getAncVisit(), true); + ANCVisit ancVisit = new ANCVisit(); + if (!ancVisitList.isEmpty()) { + ancVisit = ancVisitList.get(0); + } + logger.info("ANC visit fetch completed"); if (ancVisit != null) { + + logger.info("Existing ANC visit found for BenId: {}", it.getBenId()); + Long id = ancVisit.getId(); modelMapper.map(it, ancVisit); ancVisit.setId(id); + } else { + + logger.info("New ANC visit will be created for BenId: {}", it.getBenId()); + ancVisit = new ANCVisit(); modelMapper.map(it, ancVisit); ancVisit.setId(null); Long benRegId = beneficiaryRepo.getRegIDFromBenId(it.getBenId()); + logger.info("Beneficiary Reg Id fetched: {}", benRegId); + // Saving data in BenVisitDetails table - PregnantWomanRegister pwr = pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(it.getBenId(), true); + PregnantWomanRegister pwr = pregnantWomanRegisterRepo + .findPregnantWomanRegisterByBenIdAndIsActive(it.getBenId(), true); + + logger.info("PregnantWomanRegister fetched"); + BenVisitDetail benVisitDetail = new BenVisitDetail(); modelMapper.map(it, benVisitDetail); + benVisitDetail.setBeneficiaryRegId(benRegId); benVisitDetail.setVisitCategory("ANC"); benVisitDetail.setVisitReason("Follow Up"); @@ -163,37 +216,70 @@ public String saveANCVisit(List ancVisitDTOs) { benVisitDetail.setModifiedBy(it.getUpdatedBy()); benVisitDetail.setLastModDate(it.getUpdatedDate()); benVisitDetail.setProviderServiceMapID(it.getProviderServiceMapID()); + + logger.info("Saving BenVisitDetail"); + benVisitDetail = benVisitDetailsRepo.save(benVisitDetail); + logger.info("BenVisitDetail saved with id: {}", benVisitDetail.getBenVisitId()); + // Saving Data in AncCare table AncCare ancCare = new AncCare(); modelMapper.map(it, ancCare); + ancCare.setBenVisitId(benVisitDetail.getBenVisitId()); ancCare.setBeneficiaryRegId(benRegId); + if (pwr != null) { + + logger.info("LMP found calculating EDD"); + ancCare.setLastMenstrualPeriodLmp(pwr.getLmpDate()); + Calendar cal = Calendar.getInstance(); cal.setTime(pwr.getLmpDate()); cal.add(Calendar.DAY_OF_WEEK, 280); + ancCare.setExpectedDateofDelivery(new Timestamp(cal.getTime().getTime())); } + ancCare.setTrimesterNumber(it.getAncVisit().shortValue()); ancCare.setModifiedBy(it.getUpdatedBy()); ancCare.setLastModDate(it.getUpdatedDate()); ancCare.setProcessed("N"); + ancCareList.add(ancCare); + + logger.info("AncCare added to list"); } + ancList.add(ancVisit); + logger.info("ANCVisit added to list"); + }); + logger.info("Saving ANCVisit list"); + ancVisitRepo.saveAll(ancList); + + logger.info("ANCVisit saved successfully"); + + logger.info("Saving AncCare list"); + ancCareRepo.saveAll(ancCareList); - checkAndAddIncentives(ancList); + + logger.info("AncCare saved successfully"); + logger.info("ANC visit details saved"); + checkAndAddIncentives(ancList, userId); + return "no of anc details saved: " + ancList.size(); + } catch (Exception e) { - logger.info("Saving ANC visit details failed with error : " + e.getMessage()); - logger.info("Saving ANC visit details failed with error : " + e); + + logger.error("Saving ANC visit details failed with error : {}", e.getMessage()); + logger.error("Full exception : ", e); + } return null; } @@ -232,6 +318,7 @@ public String savePmsmaRecords(List pmsmaDTOs) { }); pmsmaRepo.saveAll(pmsmaList); logger.info("PMSMA details saved"); + checkAndAddHighRisk(pmsmaList); return "No. of PMSMA records saved: " + pmsmaList.size(); @@ -268,7 +355,7 @@ private void checkAndAddHighRisk(List pmsmaList) { private void addIncentiveForHighRisk(IncentiveActivity incentiveActivity, PMSMA pmsma) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), pmsma.getCreatedDate(), pmsma.getBenId()); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), pmsma.getCreatedDate(), pmsma.getBenId(),userRepo.getUserIdByName(pmsma.getCreatedBy())); // get bene details if (record == null) { @@ -291,7 +378,7 @@ record = new IncentiveActivityRecord(); public List getPNCVisits(GetBenRequestHandler dto) { try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); - List pncVisits = pncVisitRepo.getPNCForPW(user, dto.getFromDate(), dto.getToDate()); + List pncVisits = pncVisitRepo.getPNCForPW(user); return pncVisits.stream() .map(pnc -> mapper.convertValue(pnc, PNCVisitDTO.class)) .collect(Collectors.toList()); @@ -343,7 +430,7 @@ public String savePNCVisit(List pncVisitDTOs) { pncCare.setLastModDate(it.getUpdatedDate()); pncCare.setProcessed("N"); pncCareList.add(pncCare); - checkAndAddAntaraIncentive(pncList, pncVisit); + checkAndAddAntaraIncentive(pncVisit); } pncList.add(pncVisit); }); @@ -357,218 +444,431 @@ public String savePNCVisit(List pncVisitDTOs) { return null; } - private void checkAndAddAntaraIncentive(List recordList, PNCVisit ect) { - Integer userId = userRepo.getUserIdByName(ect.getCreatedBy()); - logger.info("ContraceptionMethod:" + ect.getContraceptionMethod()); + @Override + @Transactional + public String saveANCVisitQuestions(List dtos, String authorization) throws IEMRException { + Integer userId = jwtUtil.extractUserId(authorization); + String userName = userRepo.getUserNamedByUserId(userId); - if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("MALE STERILIZATION")) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + List entities = new ArrayList<>(); - IncentiveActivity maleSterilizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); + for (AncCounsellingCareDTO dto : dtos) { - IncentiveActivity maleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); - if (maleSterilizationActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, maleSterilizationActivityAM); - } - if (maleSterilizationActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, maleSterilizationActivityCH); + if (!StringUtils.hasText(dto.getVisitDate())) { + throw new IllegalArgumentException("visitDate is mandatory"); } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { - - IncentiveActivity femaleSterilizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); - - IncentiveActivity femaleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - if (femaleSterilizationActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, femaleSterilizationActivityAM); + AncCounsellingCareListDTO fields = dto.getFields(); + if (fields == null) { + throw new IllegalArgumentException("fields object is mandatory"); } - if (femaleSterilizationActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, femaleSterilizationActivityCH); + LocalDate visitDate; + try { + visitDate = LocalDate.parse(dto.getVisitDate(), formatter); + } catch (DateTimeParseException e) { + throw new IllegalArgumentException("Invalid visitDate format, expected dd-MM-yyyy"); } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("MiniLap")) { - IncentiveActivity miniLapActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MINILAP", GroupName.FAMILY_PLANNING.getDisplayName()); - if (miniLapActivity != null) { - addIncenticeRecord(recordList, ect, userId, miniLapActivity); + LocalDate homeVisitDate; + try { + homeVisitDate = StringUtils.hasText(fields.getHomeVisitDate()) + ? LocalDate.parse(fields.getHomeVisitDate(), formatter) + : visitDate; // ✅ fallback + } catch (DateTimeParseException e) { + throw new IllegalArgumentException("Invalid home_visit_date format, expected dd-MM-yyyy"); } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("Condom")) { - IncentiveActivity comdomActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", GroupName.FAMILY_PLANNING.getDisplayName()); - if (comdomActivity != null) { - addIncenticeRecord(recordList, ect, userId, comdomActivity); - } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD) WITHIN 48 HRS OF DELIVERY")) { + AncCounsellingCare entity = new AncCounsellingCare(); + entity.setBeneficiaryId(dto.getBeneficiaryId()); + entity.setAncVisitId(0L); + entity.setVisitDate(visitDate); + entity.setHomeVisitDate(homeVisitDate); + + entity.setSelectAll(yesNoToBoolean(fields.getSelectAll())); + entity.setSwelling(yesNoToBoolean(fields.getSwelling())); + entity.setHighBp(yesNoToBoolean(fields.getHighBp())); + entity.setConvulsions(yesNoToBoolean(fields.getConvulsions())); + entity.setAnemia(yesNoToBoolean(fields.getAnemia())); + entity.setReducedFetalMovement(yesNoToBoolean(fields.getReducedFetalMovement())); + entity.setAgeRisk(yesNoToBoolean(fields.getAgeRisk())); + entity.setChildGap(yesNoToBoolean(fields.getChildGap())); + entity.setShortHeight(yesNoToBoolean(fields.getShortHeight())); + entity.setPrePregWeight(yesNoToBoolean(fields.getPrePregWeight())); + entity.setBleeding(yesNoToBoolean(fields.getBleeding())); + entity.setMiscarriageHistory(yesNoToBoolean(fields.getMiscarriageHistory())); + entity.setFourPlusDelivery(yesNoToBoolean(fields.getFourPlusDelivery())); + entity.setFirstDelivery(yesNoToBoolean(fields.getFirstDelivery())); + entity.setTwinPregnancy(yesNoToBoolean(fields.getTwinPregnancy())); + entity.setCSectionHistory(yesNoToBoolean(fields.getCSectionHistory())); + entity.setPreExistingDisease(yesNoToBoolean(fields.getPreExistingDisease())); + entity.setFeverMalaria(yesNoToBoolean(fields.getFeverMalaria())); + entity.setJaundice(yesNoToBoolean(fields.getJaundice())); + entity.setSickleCell(yesNoToBoolean(fields.getSickleCell())); + entity.setProlongedLabor(yesNoToBoolean(fields.getProlongedLabor())); + entity.setMalpresentation(yesNoToBoolean(fields.getMalpresentation())); + + entity.setUserId(userId); + entity.setCreatedBy(userName); + entity.setUpdatedBy(userName); + + entities.add(entity); + } - IncentiveActivity PPIUCDActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + ancCounsellingCareRepo.saveAll(entities); - IncentiveActivity PPIUCDActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.ACTIVITY.getDisplayName()); - if (PPIUCDActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, PPIUCDActivityAM); - } + return "ANC Counselling & Care data saved successfully"; + } - if (PPIUCDActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, PPIUCDActivityCH); - } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)")) { - IncentiveActivity ppsActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.FAMILY_PLANNING.getDisplayName()); + @Override + public List getANCCounselling(GetBenRequestHandler requestDTO) { + + List entities = + ancCounsellingCareRepo.findAllByUserId(requestDTO.getAshaId()); + + List responseDTOList = new ArrayList<>(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + + for (AncCounsellingCare entity : entities) { + + AncCounsellingCareResponseDTO responseDTO = new AncCounsellingCareResponseDTO(); + responseDTO.setFormId("anc_form_001"); + responseDTO.setBeneficiaryId(entity.getBeneficiaryId()); // Update with actual value + responseDTO.setVisitDate(entity.getVisitDate().format(formatter)); // Format visit.getVisitDate() + + // 🔹 fields map + Map fields = new HashMap<>(); + + fields.put("home_visit_date", + entity.getHomeVisitDate() != null + ? entity.getHomeVisitDate().format(formatter) + : null); + + fields.put("select_all", booleanToYesNo(entity.getSelectAll())); + fields.put("swelling", booleanToYesNo(entity.getSwelling())); + fields.put("high_bp", booleanToYesNo(entity.getHighBp())); + fields.put("convulsions", booleanToYesNo(entity.getConvulsions())); + fields.put("anemia", booleanToYesNo(entity.getAnemia())); + fields.put("reduced_fetal_movement", booleanToYesNo(entity.getReducedFetalMovement())); + fields.put("age_risk", booleanToYesNo(entity.getAgeRisk())); + fields.put("child_gap", booleanToYesNo(entity.getChildGap())); + fields.put("short_height", booleanToYesNo(entity.getShortHeight())); + fields.put("pre_preg_weight", booleanToYesNo(entity.getPrePregWeight())); + fields.put("bleeding", booleanToYesNo(entity.getBleeding())); + fields.put("miscarriage_history", booleanToYesNo(entity.getMiscarriageHistory())); + fields.put("four_plus_delivery", booleanToYesNo(entity.getFourPlusDelivery())); + fields.put("first_delivery", booleanToYesNo(entity.getFirstDelivery())); + fields.put("twin_pregnancy", booleanToYesNo(entity.getTwinPregnancy())); + fields.put("c_section_history", booleanToYesNo(entity.getCSectionHistory())); + fields.put("pre_existing_disease", booleanToYesNo(entity.getPreExistingDisease())); + fields.put("fever_malaria", booleanToYesNo(entity.getFeverMalaria())); + fields.put("jaundice", booleanToYesNo(entity.getJaundice())); + fields.put("sickle_cell", booleanToYesNo(entity.getSickleCell())); + fields.put("prolonged_labor", booleanToYesNo(entity.getProlongedLabor())); + fields.put("malpresentation", booleanToYesNo(entity.getMalpresentation())); + + responseDTO.setFields(fields); + responseDTOList.add(responseDTO); - IncentiveActivity ppsActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.ACTIVITY.getDisplayName()); - if (ppsActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, ppsActivityAM); - } - if (ppsActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, ppsActivityCH); - } } + return responseDTOList; } - private void addIncenticeRecord(List recordList, PNCVisit ect, Integer userId, IncentiveActivity antaraActivity) { - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getCreatedDate(), ect.getBenId()); - // get bene details + private String booleanToYesNo(Boolean value) { + return Boolean.TRUE.equals(value) ? "Yes" : "No"; + } - if (record == null) { - record = new IncentiveActivityRecord(); - record.setActivityId(antaraActivity.getId()); - record.setCreatedDate(ect.getPncDate()); - record.setCreatedBy(ect.getCreatedBy()); - record.setStartDate(ect.getPncDate()); - record.setEndDate(ect.getPncDate()); - record.setUpdatedDate(ect.getPncDate()); - record.setUpdatedBy(ect.getCreatedBy()); - record.setBenId(ect.getBenId()); - record.setAshaId(userId); - record.setAmount(Long.valueOf(antaraActivity.getRate())); - recordRepo.save(record); - } + + private Boolean yesNoToBoolean(String value) { + return "Yes".equalsIgnoreCase(value); } - private void checkAndAddIncentives(List ancList) { + private void checkAndAddAntaraIncentive(PNCVisit ect) { + Integer userId = userRepo.getUserIdByName(ect.getCreatedBy()); + Integer stateId = userRepo.getUserRole(userId).get(0).getStateId(); + logger.info("ContraceptionMethod:" + ect.getContraceptionMethod()); - IncentiveActivity anc1Activity = - incentivesRepo.findIncentiveMasterByNameAndGroup("ANC_REGISTRATION_1ST_TRIM", GroupName.MATERNAL_HEALTH.getDisplayName()); + // logic for assam + if (stateId.equals(StateCode.AM.getStateCode())) { + if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("MALE STERILIZATION")) { - IncentiveActivity ancFullActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FULL_ANC", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity maleSterilizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); - IncentiveActivity ancFullActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("ANC_FOUR_CHECKUPS_SUPPORT", GroupName.ACTIVITY.getDisplayName()); + if (maleSterilizationActivityAM != null) { + addIncenticeRecord(ect, userId, maleSterilizationActivityAM); + } - IncentiveActivity comprehensiveAbortionActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("COMPREHENSIVE_ABORTION_CARE", GroupName.MATERNAL_HEALTH.getDisplayName()); - IncentiveActivity comprehensiveAbortionActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("COMPREHENSIVE_ABORTION_CARE", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity identifiedHrpActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("EPMSMA_HRP_IDENTIFIED", GroupName.MATERNAL_HEALTH.getDisplayName()); - IncentiveActivity identifiedHrpActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("EPMSMA_HRP_IDENTIFIED", GroupName.ACTIVITY.getDisplayName()); + } + if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { - IncentiveActivity paiucdActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PAIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + IncentiveActivity femaleSterilizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); + if (femaleSterilizationActivityAM != null) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityAM); + } - IncentiveActivity paiucdActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PAIUCD", GroupName.ACTIVITY.getDisplayName()); + } + if (ect.getContraceptionMethod() != null && (ect.getContraceptionMethod().equals("MiniLap") || ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)"))) { - ancList.forEach(ancVisit -> { - if (paiucdActivityAM != null) { - if (ancVisit.getIsPaiucd()!= null) { - if (ancVisit.getIsPaiucd().equals("Yes")) { - recordAncRelatedIncentive(paiucdActivityAM, ancVisit); + IncentiveActivity miniLapActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.FAMILY_PLANNING.getDisplayName()); + if (miniLapActivity != null) { + addIncenticeRecord(ect, userId, miniLapActivity); + } + } + if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("Condom")) { - } + IncentiveActivity comdomActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", GroupName.FAMILY_PLANNING.getDisplayName()); + if (comdomActivity != null) { + addIncenticeRecord(ect, userId, comdomActivity); + } + } + if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD) WITHIN 48 HRS OF DELIVERY")) { + + IncentiveActivity PPIUCDActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + + if (PPIUCDActivityAM != null) { + addIncenticeRecord(ect, userId, PPIUCDActivityAM); } } - if (paiucdActivityCH != null) { - if (ancVisit.getIsPaiucd()!= null) { - if (ancVisit.getIsPaiucd().equals("Yes")) { + } + // logic for cg + if (stateId.equals(StateCode.CG.getStateCode())) { + if (ect.getAnyContraceptionMethod() != null) { + if (ect.getAnyContraceptionMethod()) { + IncentiveActivity femaleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - recordAncRelatedIncentive(paiucdActivityCH, ancVisit); + IncentiveActivity PPIUCDActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.ACTIVITY.getDisplayName()); + + IncentiveActivity maleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); + + + if (PPIUCDActivityCH != null) { + if (ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD)")) { + addIncenticeRecord(ect, userId, PPIUCDActivityCH); + + } } - } - } - if (anc1Activity != null) { - if (ancVisit.getAncVisit() != null) { + if (femaleSterilizationActivityCH != null) { + if (ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityCH); - if (ancVisit.getAncVisit() == 1) { - recordAncRelatedIncentive(anc1Activity, ancVisit); + } + } + + + if (maleSterilizationActivityCH != null) { + if (ect.getContraceptionMethod().equals("MALE STERILIZATION")) { + addIncenticeRecord(ect, userId, maleSterilizationActivityCH); + + } } } + } - if (ancFullActivityAM != null) { - if (ancVisit.getAncVisit() == 4 || ancVisit.getAncVisit() == 2 || ancVisit.getAncVisit() == 3) { - recordAncRelatedIncentive(ancFullActivityAM, ancVisit); + + if (ect.getMotherDangerSign() != null + && !ect.getMotherDangerSign().isEmpty() + && ect.getPncPeriod() == 42) { + IncentiveActivity highRiskPostpartumCareActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); + if (highRiskPostpartumCareActivityCH != null) { + addIncenticeRecord(ect, userId, highRiskPostpartumCareActivityCH); + } } - if (ancFullActivityCH != null) { - if (ancVisit.getAncVisit() != null) { - if (ancVisit.getAncVisit() == 4) { - recordAncRelatedIncentive(ancFullActivityCH, ancVisit); - } + if (ect.getPncPeriod() == 42) { + IncentiveActivity highRiskPostpartumHealthCareActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); + + if (highRiskPostpartumHealthCareActivityCH != null) { + addIncenticeRecord(ect, userId, highRiskPostpartumHealthCareActivityCH); + } + } - if (comprehensiveAbortionActivityAM != null) { - if (ancVisit.getIsAborted() != null) { - if (ancVisit.getIsAborted()) { - recordAncRelatedIncentive(comprehensiveAbortionActivityAM, ancVisit); + if (ect.getPncPeriod() == 1 || ect.getPncPeriod() == 3 || ect.getPncPeriod() == 7) { + + if ((ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)") + || ect.getContraceptionMethod().equals("MiniLap")) + && ect.getSterilisationDate() != null) { + IncentiveActivity ppsActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.ACTIVITY.getDisplayName()); + if (ppsActivityCH != null) { + + addIncenticeRecord(ect, userId, ppsActivityCH); + } } + } + + } + + + } + + + @Transactional + private void addIncenticeRecord(PNCVisit ect, Integer userId, IncentiveActivity antaraActivity) { + + String lockKey = antaraActivity.getId() + "_" + ect.getBenId() + "_" + ect.getPncDate(); + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + synchronized (lock) { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getPncDate(), ect.getBenId(),userId); + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(antaraActivity.getId()); + record.setCreatedDate(ect.getPncDate()); + record.setCreatedBy(ect.getCreatedBy()); + record.setStartDate(ect.getPncDate()); + record.setEndDate(ect.getPncDate()); + record.setUpdatedDate(ect.getPncDate()); + record.setUpdatedBy(ect.getCreatedBy()); + record.setBenId(ect.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(antaraActivity.getRate())); + recordRepo.save(record); } + } + + lockMap.remove(lockKey, lock); + } + + + private void checkAndAddIncentives(List ancList, Integer userId) { - if (comprehensiveAbortionActivityCH != null) { - if (ancVisit.getIsAborted() != null) { - if (ancVisit.getIsAborted()) { - recordAncRelatedIncentive(comprehensiveAbortionActivityCH, ancVisit); + Integer stateId = userRepo.getUserRole(userId).get(0).getStateId(); + + + // ✅ State 5 — Assam + if (stateId.equals(5)) { + IncentiveActivity anc1Activity = incentivesRepo.findIncentiveMasterByNameAndGroup( + "ANC_REGISTRATION_1ST_TRIM", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity ancFullActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FULL_ANC", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity identifiedHrpActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("EPMSMA_HRP_IDENTIFIED", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity comprehensiveAbortionActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "COMPREHENSIVE_ABORTION_CARE", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity paiucdActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_PAIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + + IncentiveActivity iucdActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_IUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + ancList.forEach(ancVisit -> { + if(ancVisit.getIsAborted()){ + if (paiucdActivityAM != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==2 && + ancVisit.getIsPaiucd().toString().contains("Tubectomy")) { + recordAncRelatedIncentive(paiucdActivityAM, ancVisit); + } + if (iucdActivityAM != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==1 && + ancVisit.getIsPaiucd().toString().contains("Copper-T")) { + recordAncRelatedIncentive(iucdActivityAM, ancVisit); } } - } - if (identifiedHrpActivityAM != null) { - if (ancVisit.getIsHrpConfirmed() != null) { - if (ancVisit.getIsHrpConfirmed()) { - recordAncRelatedIncentive(identifiedHrpActivityAM, ancVisit); - } + + + if (anc1Activity != null && ancVisit.getAncVisit() != null + && ancVisit.getAncVisit() == 1) { + recordAncFirstTRIMIncentive(anc1Activity, ancVisit); + } + + if (ancFullActivityAM != null && ancVisit.getAncVisit() != null + && ancVisit.getAncVisit() == 4) { + recordFullAncIncentive(ancFullActivityAM, ancVisit); + } + + + if (comprehensiveAbortionActivityAM != null && ancVisit.getIsAborted() != null + && ancVisit.getIsAborted()) { + recordAncRelatedIncentive(comprehensiveAbortionActivityAM, ancVisit); + } + + + if (identifiedHrpActivityAM != null && ancVisit.getIsHrpConfirmed() != null + && ancVisit.getIsHrpConfirmed()) { + recordAncRelatedIncentive(identifiedHrpActivityAM, ancVisit); } - } - if (identifiedHrpActivityCH != null) { - if (ancVisit.getIsHrpConfirmed() != null) { - if (ancVisit.getIsHrpConfirmed()) { - recordAncRelatedIncentive(identifiedHrpActivityCH, ancVisit); + }); + } + + // ✅ State 8 + if (stateId.equals(8)) { + + IncentiveActivity ancFullActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "ANC_FOUR_CHECKUPS_SUPPORT", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity comprehensiveAbortionActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "COMPREHENSIVE_ABORTION_CARE", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity identifiedHrpActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "EPMSMA_HRP_IDENTIFIED", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity paiucdActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_PAIUCD", GroupName.ACTIVITY.getDisplayName()); + + IncentiveActivity iucdActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_IUCD", GroupName.ACTIVITY.getDisplayName()); + + ancList.forEach(ancVisit -> { + + + if (ancVisit.getIsAborted()) { + if (paiucdActivityCH != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==2 && + ancVisit.getIsPaiucd().toString().contains("Tubectomy")) { + recordAncRelatedIncentive(paiucdActivityCH, ancVisit); + } + if (iucdActivityCH != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==1 + && ancVisit.getIsPaiucd().toString().contains("Copper-T")) { + recordAncRelatedIncentive(iucdActivityCH, ancVisit); } } - } - }); + if (ancFullActivityCH != null && ancVisit.getAncVisit() != null + && ancVisit.getAncVisit() == 4) { + recordAncRelatedIncentive(ancFullActivityCH, ancVisit); + } + + + if (identifiedHrpActivityCH != null && ancVisit.getIsHrpConfirmed() != null + && ancVisit.getIsHrpConfirmed()) { + recordAncRelatedIncentive(identifiedHrpActivityCH, ancVisit); + } + }); + } } private void recordAncRelatedIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { - IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), ancVisit.getCreatedDate(), ancVisit.getBenId()); Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), ancVisit.getCreatedDate(), ancVisit.getBenId(),userId); + if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(incentiveActivity.getId()); @@ -586,6 +886,74 @@ record = new IncentiveActivityRecord(); } + private void recordAncFirstTRIMIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { + Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); + + if (ancVisit.getAncDate() == null || ancVisit.getLmpDate() == null) { + return; + } + + LocalDate ancLocalDate = ancVisit.getAncDate().toLocalDateTime().toLocalDate(); + LocalDate lmpLocalDate = ancVisit.getLmpDate().toLocalDateTime().toLocalDate(); + + long weeksBetween = ChronoUnit.WEEKS.between(lmpLocalDate, ancLocalDate); + + if (weeksBetween < 0 || weeksBetween >= 12) { + return; + } + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + ancVisit.getCreatedDate(), + ancVisit.getBenId(),userId + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(ancVisit.getLmpDate()); + record.setCreatedBy(ancVisit.getCreatedBy()); + record.setUpdatedDate(ancVisit.getLmpDate()); + record.setUpdatedBy(ancVisit.getCreatedBy()); + record.setStartDate(ancVisit.getLmpDate()); + record.setEndDate(ancVisit.getLmpDate()); + record.setBenId(ancVisit.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } + + private void recordFullAncIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { + Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); + if (userId == null) { + return; + } + IncentiveActivityRecord existRecord = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + ancVisit.getAncDate(), + ancVisit.getBenId(),userId + ); + + + if (existRecord != null) { + return; + } + + IncentiveActivityRecord record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(ancVisit.getAncDate()); + record.setCreatedBy(ancVisit.getCreatedBy()); + record.setUpdatedDate(ancVisit.getAncDate()); + record.setUpdatedBy(ancVisit.getCreatedBy()); + record.setStartDate(ancVisit.getAncDate()); + record.setEndDate(ancVisit.getAncDate()); + record.setBenId(ancVisit.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } public void sendAncDueTomorrowNotifications(String ashaId) { try { diff --git a/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java b/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java index a5b6dd779..21d0da458 100644 --- a/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java +++ b/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java @@ -1,19 +1,13 @@ package com.iemr.flw.service.impl; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.service.EmployeeMasterInter; -import com.iemr.flw.service.impl.ChildCareServiceImpl; -import com.iemr.flw.service.impl.MaternalHealthServiceImpl; import com.iemr.flw.utils.CookieUtil; -import jakarta.annotation.PostConstruct; -import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; @Service public class NotificationSchedulerService { @@ -61,7 +55,7 @@ public void triggerAncRemindersForAllAsha() { @Scheduled(cron = "0 0 9 * * *") public void trigerTomorrowImmunizationReminders() { - for(M_User m_user: employeeMasterInter.getAllUsers()){ + for(User m_user: employeeMasterInter.getAllUsers()){ childCareService.getTomorrowImmunizationReminders(m_user.getUserID()); } diff --git a/src/main/java/com/iemr/flw/service/impl/SammelanServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SammelanServiceImpl.java index 53497981a..e0460fe8d 100644 --- a/src/main/java/com/iemr/flw/service/impl/SammelanServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SammelanServiceImpl.java @@ -51,6 +51,8 @@ public class SammelanServiceImpl implements SammelanService { @Autowired private IncentivesRepo incentivesRepo; + @Autowired + private UpdateIncentivePendindDocService updateIncentivePendindDocService; @Override @@ -62,36 +64,36 @@ public SammelanResponseDTO submitSammelan(SammelanRequestDTO sammelanRequestDTO) // Save Sammelan record record = new SammelanRecord(); record.setAshaId(sammelanRequestDTO.getAshaId()); - logger.info("Meeting Date:"+sammelanRequestDTO.getDate()); + logger.info("Meeting Date:" + sammelanRequestDTO.getDate()); Timestamp timestamp = new Timestamp(sammelanRequestDTO.getDate()); record.setMeetingDate(timestamp); record.setPlace(sammelanRequestDTO.getPlace()); record.setParticipants(sammelanRequestDTO.getParticipants()); - if (sammelanRequestDTO.getSammelanImages() != null && sammelanRequestDTO.getSammelanImages().length > 0) { - List base64Images = Arrays.stream(sammelanRequestDTO.getSammelanImages()) - .filter(file -> !file.isEmpty()) - .map(file -> { - try { - return Base64.getEncoder().encodeToString(file.getBytes()); - } catch (IOException e) { - throw new RuntimeException("Error converting image to Base64", e); - } - }) - .collect(Collectors.toList()); - - String imagesJson = objectMapper.writeValueAsString(base64Images); - record .setAttachments(imagesJson); - } + if (sammelanRequestDTO.getSammelanImages() != null && sammelanRequestDTO.getSammelanImages().length > 0) { + List base64Images = Arrays.stream(sammelanRequestDTO.getSammelanImages()) + .filter(file -> !file.isEmpty()) + .map(file -> { + try { + return Base64.getEncoder().encodeToString(file.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Error converting image to Base64", e); + } + }) + .collect(Collectors.toList()); - if(record!=null){ - record = recordRepo.save(record); - checkIncentive(record); + String imagesJson = objectMapper.writeValueAsString(base64Images); + record.setAttachments(imagesJson); + } + + if (record != null) { + record = recordRepo.save(record); + checkIncentive(record); - } - // Prepare Response DTO + } + // Prepare Response DTO response.setId(record.getId()); response.setAshaId(record.getAshaId()); Timestamp ts = Timestamp.valueOf(record.getMeetingDate().toLocalDateTime()); @@ -103,7 +105,7 @@ record = recordRepo.save(record); } catch (Exception e) { - logger.info("SammelanRecord Exception: "+e.getMessage()); + logger.info("SammelanRecord Exception: " + e.getMessage()); } return response; @@ -112,31 +114,43 @@ record = recordRepo.save(record); private void checkIncentive(SammelanRecord record) { IncentiveActivity incentiveActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("FP_SAAS_BAHU", GroupName.FAMILY_PLANNING.getDisplayName()); - logger.info("SammelanRecord: "+incentiveActivity.getRate()); - if(incentiveActivity!=null){ - addSammelanIncentive(incentiveActivity,record); + logger.info("SammelanRecord: " + incentiveActivity.getRate()); + if (incentiveActivity != null) { + addSammelanIncentive(incentiveActivity, record); } } private void addSammelanIncentive(IncentiveActivity incentiveActivity, SammelanRecord record) { - IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), record.getMeetingDate(), 0L,record.getAshaId()); + String userName = userRepo.getUserNamedByUserId(record.getAshaId()); + IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), record.getMeetingDate(), 0L, record.getAshaId()); try { if (incentiveActivityRecord == null) { incentiveActivityRecord = new IncentiveActivityRecord(); incentiveActivityRecord.setActivityId(incentiveActivity.getId()); incentiveActivityRecord.setCreatedDate(record.getMeetingDate()); - incentiveActivityRecord.setCreatedBy(userRepo.getUserNamedByUserId(record.getAshaId())); + incentiveActivityRecord.setCreatedBy(userName); incentiveActivityRecord.setStartDate(record.getMeetingDate()); incentiveActivityRecord.setEndDate(record.getMeetingDate()); incentiveActivityRecord.setUpdatedDate(record.getMeetingDate()); - incentiveActivityRecord.setUpdatedBy(userRepo.getUserNamedByUserId(record.getAshaId())); + incentiveActivityRecord.setUpdatedBy(userName); incentiveActivityRecord.setBenId(0L); incentiveActivityRecord.setAshaId(record.getAshaId()); incentiveActivityRecord.setAmount(Long.valueOf(incentiveActivity.getRate())); - incentiveRecordRepo.save(incentiveActivityRecord); + if (record.getAttachments() != null) { + incentiveActivityRecord.setIsEligible(true); + incentiveRecordRepo.save(incentiveActivityRecord); + + } else { + incentiveActivityRecord.setIsEligible(false); + IncentiveActivityRecord activityRecord = incentiveRecordRepo.save(incentiveActivityRecord); + if (activityRecord != null) { + updateIncentivePendindDocService.updatePendingActivity(record.getAshaId(), record.getId(), activityRecord.getActivityId(), incentiveActivity.getId()); + + } + } } - }catch (Exception e){ - logger.info("SammelanRecord save Record: ",e); + } catch (Exception e) { + logger.info("SammelanRecord save Record: ", e); } diff --git a/src/main/java/com/iemr/flw/service/impl/SmsSchedulerService.java b/src/main/java/com/iemr/flw/service/impl/SmsSchedulerService.java index 637d011a2..90b57fdd3 100644 --- a/src/main/java/com/iemr/flw/service/impl/SmsSchedulerService.java +++ b/src/main/java/com/iemr/flw/service/impl/SmsSchedulerService.java @@ -2,22 +2,16 @@ import com.iemr.flw.domain.identity.RMNCHBeneficiaryDetailsRmnch; import com.iemr.flw.domain.iemr.ANCVisit; -import com.iemr.flw.domain.iemr.M_User; -import com.iemr.flw.dto.iemr.ANCVisitDTO; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.ANCVisitRepo; import com.iemr.flw.service.EmployeeMasterInter; import com.iemr.flw.utils.CookieUtil; -import jakarta.annotation.PostConstruct; -import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; import java.math.BigInteger; import java.sql.Timestamp; @@ -25,7 +19,6 @@ import java.time.ZoneId; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; @Service public class SmsSchedulerService { @@ -94,7 +87,7 @@ public void sendAncReminders() { @Scheduled(cron = "0 0 9 * * *") public void trigerTomorrowImmunizationReminders() { - for (M_User m_user : employeeMasterInter.getAllUsers()) { + for (User m_user : employeeMasterInter.getAllUsers()) { childCareService.getTomorrowImmunizationReminders(m_user.getUserID()); } diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java new file mode 100644 index 000000000..771810e20 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -0,0 +1,437 @@ +package com.iemr.flw.service.impl; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.dto.iemr.UserServiceRoleDTO; +import com.iemr.flw.masterEnum.IncentiveApprovalStatus; +import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.iemr.flw.service.SupervisorDashboardService; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class SupervisorDashboardServiceImpl implements SupervisorDashboardService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired + private SupervisorDashboardRepo dashboardRepo; + + @Autowired + private AshaSupervisorLoginRepo ashaSupervisorLoginRepo; + + @Autowired + private FacilityLoginRepo facilityLoginRepo; + + @Autowired + private IncentiveRecordRepo incentiveRecordRepo; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserService userService; + + @Override + public String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year) { + JSONObject result = new JSONObject(); + + // 1. Supervisor user details + List supervisorRows = dashboardRepo.getSupervisorUserDetails(supervisorUserID); + if (supervisorRows != null && !supervisorRows.isEmpty()) { + Object[] sRow = supervisorRows.get(0); + JSONObject supervisor = new JSONObject(); + supervisor.put("userId", sRow[0]); + supervisor.put("fullName", fullName(sRow[1], sRow[2])); + supervisor.put("employeeId", str(sRow[3]).isEmpty() ? JSONObject.NULL : str(sRow[3])); + supervisor.put("mobile", str(sRow[4]).isEmpty() ? JSONObject.NULL : str(sRow[4])); + supervisor.put("gender", str(sRow[5]).isEmpty() ? JSONObject.NULL : str(sRow[5])); + result.put("supervisor", supervisor); + } + + // 2. Get all ASHAs with facility info + List ashaRows = dashboardRepo.getAshasWithFacilityInfo(supervisorUserID); + if (ashaRows == null || ashaRows.isEmpty()) { + result.put("totalAshaCount", 0); + result.put("incentiveSummary", buildEmptyIncentiveSummary()); + result.put("facilities", new JSONArray()); + return result.toString(); + } + + // Collect distinct facility IDs and ASHA IDs + Set facilityIDSet = new HashSet<>(); + Set ashaIDSet = new HashSet<>(); + for (Object[] row : ashaRows) { + if (row[3] != null) + facilityIDSet.add((Integer) row[3]); + if (row[0] != null) + ashaIDSet.add((Integer) row[0]); + } + List facilityIDs = new ArrayList<>(facilityIDSet); + List ashaIDs = new ArrayList<>(ashaIDSet); + + result.put("totalAshaCount", ashaIDs.size()); + + // 3. Location from first facility + List facilityRows = dashboardRepo.getFacilityDetails(facilityIDs); + if (facilityRows != null && !facilityRows.isEmpty()) { + Object[] fRow = facilityRows.get(0); + JSONObject location = new JSONObject(); + location.put("state", str(fRow[2])); + location.put("district", str(fRow[3])); + location.put("blockOrUlb", str(fRow[4])); + location.put("locationType", str(fRow[5])); + result.put("location", location); + } + + // 4. Build village map (facilityID -> villages) + Map> villageMap = new HashMap<>(); + List villageRows = dashboardRepo.getVillagesForFacilities(facilityIDs); + if (villageRows != null) { + for (Object[] vRow : villageRows) { + Integer facID = (Integer) vRow[0]; + JSONObject village = new JSONObject(); + village.put("villageId", vRow[1]); + village.put("villageName", str(vRow[2])); + villageMap.computeIfAbsent(facID, k -> new ArrayList<>()).add(village); + } + } + + // 5. Get incentive status per ASHA (verified, rejected, pending, totalAmount) + long overallVerified = 0, overallRejected = 0, overallPending = 0; + long overallUnclaimed = 0; + + try { + logger.info("Month: {}", month); + logger.info("Year: {}", year); + + LocalDate startLocalDate = LocalDate.of(year, month, 1); + LocalDate endLocalDate = startLocalDate.plusMonths(1); + + logger.info("startLocalDate {}", startLocalDate); + logger.info("endLocalDate {}", endLocalDate); + + Timestamp startDate = Timestamp.valueOf(startLocalDate.atStartOfDay()); + Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + logger.info("Asha ID" + ashaIDs); + + List statusRows = dashboardRepo.getIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); + if (statusRows != null) { + for (Object[] sRow : statusRows) { + long verified = ((Number) sRow[2]).longValue(); + long rejected = ((Number) sRow[3]).longValue(); + long pending = ((Number) sRow[4]).longValue(); + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + } + } + List unclaimedRows = dashboardRepo.getUnclaimedCountByAshaIds(ashaIDs, startDate, endDate); + if (unclaimedRows != null) { + for (Object[] uRow : unclaimedRows) { + long count = ((Number) uRow[1]).longValue(); + if (count > 0) overallUnclaimed += 1; + } + } + } catch (Exception e) { + logger.error("Error fetching incentive status: " + e.getMessage(), e); + } + + + + // Overall incentive summary across all ASHAs + JSONObject overallSummary = new JSONObject(); + overallSummary.put("verified", overallVerified); + overallSummary.put("rejected", overallRejected); + overallSummary.put("pending", overallPending); + overallSummary.put("overDue", 0); + overallSummary.put("unclaimed", overallUnclaimed); + result.put("incentiveSummary", overallSummary); + + // 7. Build facilities array with nested ASHAs + Map> ashasByFacility = new HashMap<>(); + for (Object[] row : ashaRows) { + Integer facID = (Integer) row[3]; + ashasByFacility.computeIfAbsent(facID, k -> new ArrayList<>()).add(row); + } + + Map facilityDetailsMap = new HashMap<>(); + if (facilityRows != null) { + for (Object[] fRow : facilityRows) { + facilityDetailsMap.put((Integer) fRow[0], fRow); + } + } + + JSONArray facilitiesArray = new JSONArray(); + for (Integer facID : facilityIDs) { + JSONObject facility = new JSONObject(); + facility.put("facilityId", facID); + + Object[] fDetails = facilityDetailsMap.get(facID); + if (fDetails != null) { + facility.put("facilityName", str(fDetails[1])); + facility.put("facilityType", str(fDetails[6])); + } + + + // ASHAs at this facility + JSONArray ashasArray = new JSONArray(); + List facAshaRows = ashasByFacility.get(facID); + if (facAshaRows != null) { + for (Object[] row : facAshaRows) { + Integer ashaId = (Integer) row[0]; + JSONObject asha = new JSONObject(); + asha.put("userId", ashaId); + asha.put("fullName", fullName(row[1], row[2])); + asha.put("employeeId", str(row[6]).isEmpty() ? JSONObject.NULL : str(row[6])); + asha.put("mobile", str(row[7]).isEmpty() ? JSONObject.NULL : str(row[7])); + asha.put("gender", str(row[8]).isEmpty() ? JSONObject.NULL : str(row[8])); + + ashasArray.put(asha); + } + } + + facility.put("ashaCount", ashasArray.length()); + facilitiesArray.put(facility); + } + + result.put("facilities", facilitiesArray); + return result.toString(); + } + + @Override + public Map getAshasAtFacility(Integer supervisorId, Integer facilityId, + Integer month, Integer year, Integer approvalStatusID) { + List rows; + logger.info("approvalStatusID:" + approvalStatusID); + + List superVisorRow = ashaSupervisorLoginRepo.getAllMappedAshas(supervisorId); + + List> ashaList = new ArrayList<>(); + + LocalDate startLocalDate = LocalDate.of(year, month, 1); + LocalDate endLocalDate = startLocalDate.plusMonths(1); + + Timestamp startDate = Timestamp.valueOf(startLocalDate.atStartOfDay()); + Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + + if (facilityId.equals(0)) { + rows = ashaSupervisorLoginRepo.getAshasAtFacility( + supervisorId, approvalStatusID, startDate, endDate); + } else { + rows = ashaSupervisorLoginRepo.getAshasAtFacility( + supervisorId, facilityId, approvalStatusID, startDate, endDate); + } + + long overallVerified = 0, overallRejected = 0, overallPending = 0; + + String facilityName = ""; + String facilityType = ""; + Integer facilityID = null; + + for (Object[] row : superVisorRow) { + facilityID = (Integer) row[3]; + facilityName = str(row[4]); + facilityType = str(row[5]); + } + + for (Object[] row : rows) { + + Map asha = new HashMap<>(); + + Integer ashaId = ((Number) row[0]).intValue(); + + List countList = incentiveRecordRepo.getStatusCountByAshaId(ashaId, startDate, endDate); + Long totalAmount = null; + if (userService.getUserDetail(ashaId) != null) { + Integer stateCode = userService.getUserDetail(ashaId).getStateId(); + totalAmount = incentiveRecordRepo.getTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); + + } + + + List incentiveActivityRecord = + incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate) + .stream() + .filter(r -> approvalStatusID == 0 || + approvalStatusID.equals(r.getApprovalStatus())) + .collect(Collectors.toList()); + List> activityList = new ArrayList<>(); + for (IncentiveActivityRecord record : incentiveActivityRecord) { + Map activity = new HashMap<>(); + activity.put("reason", record.getReason()); + activity.put("otherReason", record.getOtherReason()); + activity.put("approvalDate", record.getApprovalDate()); + activity.put("approvalStatus", record.getApprovalStatus()); + if(record.getVerifiedByUserId()!=null){ + activity.put("verifiedByUserName", userService.getUserDetail(record.getVerifiedByUserId()).getName()); + + } + activity.put("verifiedByUserId", record.getVerifiedByUserId()); + activity.put("isClaimed", record.getIsClaimed()); + activity.put("claimedDate", record.getCalimedDate()); + + UserServiceRoleDTO roles = userService.getUserDetail(record.getVerifiedByUserId()); + activity.put("role", (roles != null ) ? roles.getRoleName() : null); + + activityList.add(activity); + } + + asha.put("facilityId", facilityID); + asha.put("facilityName", facilityName); + asha.put("facilityType", facilityType); + asha.put("userId", row[0]); + asha.put("fullName", fullName(row[1], row[2])); + asha.put("employeeId", str(row[3]).isEmpty() ? null : str(row[3])); + asha.put("mobile", str(row[4]).isEmpty() ? null : str(row[4])); + asha.put("gender", str(row[5]).isEmpty() ? null : str(row[5])); + asha.put("totalAmount", totalAmount); + asha.put("activities", activityList); + + long pending = 0, verified = 0, rejected = 0; + if (countList != null && !countList.isEmpty()) { + Object[] counts = countList.get(0); + verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; + pending = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + rejected = counts[2] != null ? ((Number) counts[2]).longValue() : 0; + } + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + + asha.put("pending", pending); + asha.put("verified", verified); + asha.put("rejected", rejected); + + int approvalStatus = 0; + + if (!activityList.isEmpty()) { + approvalStatus = (int) activityList.get(0).get("approvalStatus"); + } + if (pending == 0 && verified == 0 && rejected == 0) continue; + if (approvalStatusID.equals(0)) { + asha.put("approvalStatus", approvalStatus); + + } else { + asha.put("approvalStatus", approvalStatusID); + + } + + ashaList.add(asha); + } + + Map response = new HashMap<>(); + + Map approvalStatus = new HashMap<>(); + approvalStatus.put("verified", overallVerified); + approvalStatus.put("pending", overallPending); + approvalStatus.put("rejected", overallRejected); + + response.put("approvalStatus", approvalStatus); + response.put("data", ashaList); + response.put("statusCode", 200); + + return response; + } + + private String getGroupNameByState(Integer stateCode) { + switch (stateCode) { + case 5: + return "! ACTIVITY"; + default: + return "ACTIVITY"; + } + } + + @Transactional + public int updateApprovalStatus(Integer ashaId, + Integer month, + Integer year, + Integer approvalStatus, + String incentiveIds, + String reason, + String otherReason, + String token) { + try { + Timestamp approvalDate = Timestamp.valueOf(LocalDateTime.now()); + + LocalDate startLocalDate = LocalDate.of(year, month, 1); + LocalDate endLocalDate = startLocalDate.plusMonths(1); + + Timestamp startDate = Timestamp.valueOf(startLocalDate.atStartOfDay()); + Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + + Integer ashaSupervisorUserId = jwtUtil.extractUserId(token); + logger.info("Asha Supervisor User Id : {}", ashaSupervisorUserId); + String ashaSupervisorUsername = userService.getUserDetail(ashaSupervisorUserId).getUserName(); + + if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { + int totalUpdated = 0; + + totalUpdated += incentiveRecordRepo.updateApprovalStatusById( + approvalStatus, + ashaSupervisorUserId, + ashaSupervisorUsername, + reason, + approvalDate, + otherReason + ); + + return totalUpdated; + } + + return incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( + ashaId, + approvalStatus, + startDate, + endDate, + approvalDate, + ashaSupervisorUserId, + ashaSupervisorUsername + ); + + } catch (Exception e) { + logger.error("Update claim :" + e.getMessage()); + e.printStackTrace(); + return 0; + } + } + + private JSONObject buildEmptyIncentiveSummary() { + JSONObject summary = new JSONObject(); + summary.put("verified", 0); + summary.put("rejected", 0); + summary.put("pending", 0); + summary.put("totalAmount", 0); + return summary; + } + + private String str(Object val) { + return val != null ? val.toString() : ""; + } + + private String fullName(Object first, Object last) { + return (str(first) + " " + str(last)).trim(); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java new file mode 100644 index 000000000..e89928def --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -0,0 +1,182 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; +import com.iemr.flw.domain.iemr.TBConfirmedCase; +import com.iemr.flw.dto.iemr.TBConfirmedCasesResponseDTO; +import com.iemr.flw.repo.iemr.TBConfirmedTreatmentRepository; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.TBConfirmedCaseService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.LocalDateAdapter; +import com.iemr.flw.utils.response.OutputResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { + + private static final Logger logger = LoggerFactory.getLogger(TBConfirmedCaseServiceImpl.class); + + private final TBConfirmedTreatmentRepository repository; + + @Autowired + private IncentiveLogicService incentiveLogicService; + + + @Autowired + private JwtUtil jwtUtil; + public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository) { + this.repository = repository; + } + + @Override + public String save(List request, String authorisation) throws Exception { + OutputResponse response = new OutputResponse(); + + try { + if (request != null) { + logger.info("Saving TB confirmed case: " + request); + + TBConfirmedCase entity = new TBConfirmedCase(); + for(TBConfirmedCaseDTO dto:request){ + entity.setBenId(dto.getBenId()); + entity.setUserId(jwtUtil.extractUserId(authorisation)); + entity.setRegimenType(dto.getRegimenType()); + entity.setTreatmentStartDate(dto.getTreatmentStartDate()); + entity.setExpectedTreatmentCompletionDate(dto.getExpectedTreatmentCompletionDate()); + entity.setFollowUpDate(dto.getFollowUpDate()); + entity.setMonthlyFollowUpDone(dto.getMonthlyFollowUpDone()); + entity.setAdherenceToMedicines(dto.getAdherenceToMedicines()); + entity.setAnyDiscomfort(dto.getAnyDiscomfort()); + entity.setTreatmentCompleted(dto.getTreatmentCompleted()); + entity.setActualTreatmentCompletionDate(dto.getActualTreatmentCompletionDate()); + entity.setTreatmentOutcome(dto.getTreatmentOutcome()); + entity.setDateOfDeath(dto.getDateOfDeath()); + entity.setPlaceOfDeath(dto.getPlaceOfDeath()); + entity.setReasonForDeath(dto.getReasonForDeath()); + entity.setReasonForNotCompleting(dto.getReasonForNotCompleting()); + if(entity!=null){ + repository.save(entity); + checkIncentive(entity); + + } + } + + response.setResponse("TB Confirmed case saved successfully"); + + } else { + response.setError(500, "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error saving TB confirmed case", e); + response.setError(5000, "Error saving TB confirmed case: " + e.getMessage()); + } + + return response.toString(); + } + + private void checkIncentive(TBConfirmedCase entity){ + String regimen = entity.getRegimenType(); + + boolean isDrTb = + "Shorter Regimen (9–12 Months)".equalsIgnoreCase(regimen) + || "Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen); + + if (Boolean.TRUE.equals(entity.getTreatmentCompleted()) + && entity.getExpectedTreatmentCompletionDate() != null) { + + + if (isDrTb) { + incentiveLogicService.incentiveForTbFollowUpIsDrTb( + entity.getBenId(), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + entity.getUserId() + ); + } else { + incentiveLogicService.incentiveForTbFollowUp( + entity.getBenId(), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + entity.getUserId() + ); + + } + + } + } + + @Override + public String getByBenId(Long benId, String authorisation) throws Exception { + OutputResponse response = new OutputResponse(); + + try { + List list = repository.findByBenId(benId); + + if (list != null && !list.isEmpty()) { + List dtoList = list.stream() + .map(this::toDTO) + .collect(Collectors.toList()); + + response.setResponse(dtoList.toString()); + list.forEach(this::checkIncentive); + + } else { + response.setError(404, "No record found for benId: " + benId); + } + + } catch (Exception e) { + logger.error("Error getting TB confirmed case by benId", e); + response.setError(5000, "Error getting TB confirmed case: " + e.getMessage()); + } + + return response.toString(); + } + + @Override + public String getByUserId(String authorisation) throws Exception { + TBConfirmedCasesResponseDTO tbConfirmedCasesResponseDTO = new TBConfirmedCasesResponseDTO(); + Integer userId = jwtUtil.extractUserId(authorisation); + List list = repository.findByUserId(userId); + tbConfirmedCasesResponseDTO.setUserId(userId); + tbConfirmedCasesResponseDTO.setTbConfirmedCases(list); + Gson gson = new GsonBuilder() + .registerTypeAdapter(LocalDate.class, new LocalDateAdapter()) + .create(); + + return gson.toJson(tbConfirmedCasesResponseDTO); + } + + // Utility: convert entity -> DTO + private TBConfirmedCaseDTO toDTO(TBConfirmedCase entity) { + TBConfirmedCaseDTO dto = new TBConfirmedCaseDTO(); + + dto.setBenId(entity.getBenId()); + dto.setUserId(entity.getUserId()); + dto.setRegimenType(entity.getRegimenType()); + dto.setTreatmentStartDate(entity.getTreatmentStartDate()); + dto.setExpectedTreatmentCompletionDate(entity.getExpectedTreatmentCompletionDate()); + dto.setFollowUpDate(entity.getFollowUpDate()); + dto.setMonthlyFollowUpDone(entity.getMonthlyFollowUpDone()); + dto.setAdherenceToMedicines(entity.getAdherenceToMedicines()); + dto.setAnyDiscomfort(entity.getAnyDiscomfort()); + dto.setTreatmentCompleted(entity.getTreatmentCompleted()); + dto.setActualTreatmentCompletionDate(entity.getActualTreatmentCompletionDate()); + dto.setTreatmentOutcome(entity.getTreatmentOutcome()); + dto.setDateOfDeath(entity.getDateOfDeath()); + dto.setPlaceOfDeath(entity.getPlaceOfDeath()); + dto.setReasonForDeath(entity.getReasonForDeath()); + dto.setReasonForNotCompleting(entity.getReasonForNotCompleting()); + + return dto; + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java index b62101693..a6c217b86 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java @@ -55,16 +55,21 @@ public String save(TBScreeningRequestDTO requestDTO) throws Exception { @Override public String getByUserId(GetBenRequestHandler request) { - List dtos = new ArrayList<>(); - List tbScreeningList = tbScreeningRepo.getByUserId(request.getAshaId(), request.getFromDate(), request.getToDate()); - tbScreeningList.forEach(tbScreening -> dtos.add(modelMapper.map(tbScreening, TBScreeningDTO.class))); - TBScreeningRequestDTO tbScreeningRequestDTO = new TBScreeningRequestDTO(); - tbScreeningRequestDTO.setTbScreeningList(dtos); - tbScreeningRequestDTO.setUserId(request.getAshaId()); - Gson gson = new GsonBuilder() - .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format - .create(); - return gson.toJson(tbScreeningRequestDTO); + try { + List dtos = new ArrayList<>(); + List tbScreeningList = tbScreeningRepo.getByUserId(request.getAshaId()); + tbScreeningList.forEach(tbScreening -> dtos.add(modelMapper.map(tbScreening, TBScreeningDTO.class))); + TBScreeningRequestDTO tbScreeningRequestDTO = new TBScreeningRequestDTO(); + tbScreeningRequestDTO.setTbScreeningList(dtos); + tbScreeningRequestDTO.setUserId(request.getAshaId()); + Gson gson = new GsonBuilder() + .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format + .create(); + return gson.toJson(tbScreeningRequestDTO); + }catch (Exception e){ + logger.error("TBScreening Exception:"+e.getMessage()); + } + return null; } } diff --git a/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java index 1b972be66..2a8c0eeb0 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java @@ -7,6 +7,7 @@ import com.iemr.flw.dto.iemr.TBSuspectedDTO; import com.iemr.flw.dto.iemr.TBSuspectedRequestDTO; import com.iemr.flw.repo.iemr.TBSuspectedRepo; +import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.TBSuspectedService; import org.modelmapper.ModelMapper; import org.slf4j.Logger; @@ -25,6 +26,9 @@ public class TBSuspectedServiceImpl implements TBSuspectedService { @Autowired private TBSuspectedRepo tbSuspectedRepo; + @Autowired + private IncentiveLogicService incentiveLogicService; + @Override public String getByBenId(Long benId, String authorisation) throws Exception { return null; @@ -49,6 +53,14 @@ public String save(TBSuspectedRequestDTO requestDTO) throws Exception { tbSuspected.setUserId(requestDTO.getUserId()); tbSuspectedRepo.save(tbSuspected); + if(tbSuspected!=null){ + if(tbSuspected.getIsConfirmed()){ + incentiveLogicService.incentiveForTbSuspected(tbSuspected.getBenId(),tbSuspected.getVisitDate(),tbSuspected.getVisitDate(),tbSuspected.getUserId()); + + } + + } + }); return "no of tb suspected items saved:" + requestDTO.getTbSuspectedList().size(); } @@ -57,7 +69,18 @@ public String save(TBSuspectedRequestDTO requestDTO) throws Exception { public String getByUserId(GetBenRequestHandler request) { List dtos = new ArrayList<>(); List tbSuspectedList = tbSuspectedRepo.getByUserId(request.getAshaId(), request.getFromDate(), request.getToDate()); - tbSuspectedList.forEach(tbSuspected -> dtos.add(modelMapper.map(tbSuspected, TBSuspectedDTO.class))); + tbSuspectedList.forEach(tbSuspected -> { + dtos.add(modelMapper.map(tbSuspected, TBSuspectedDTO.class)); + + if (tbSuspected != null && Boolean.TRUE.equals(tbSuspected.getIsConfirmed())) { + incentiveLogicService.incentiveForTbSuspected( + tbSuspected.getBenId(), + tbSuspected.getVisitDate(), + tbSuspected.getVisitDate(), + tbSuspected.getUserId() + ); + } + }); TBSuspectedRequestDTO tbSuspectedRequestDTO = new TBSuspectedRequestDTO(); tbSuspectedRequestDTO.setTbSuspectedList(dtos); tbSuspectedRequestDTO.setUserId(request.getAshaId()); diff --git a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java new file mode 100644 index 000000000..c45f18e1c --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java @@ -0,0 +1,195 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.IncentiveActivity; +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.dto.iemr.PaymentItem; +import com.iemr.flw.dto.iemr.PaymentRequest; +import com.iemr.flw.dto.iemr.Period; +import com.iemr.flw.dto.iemr.VerifiedBy; +import com.iemr.flw.repo.iemr.IncentiveRecordRepo; +import com.iemr.flw.repo.iemr.IncentivesRepo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class UTPReronaPaymentJob { + + @Autowired + private IncentiveRecordRepo recordRepo; + + @Autowired + private IncentivesRepo incentivesRepo; + + @Autowired + private UtpreronaPaymentIntegrationImpl paymentService; + + // Runs automatically on 1st of every month at midnight + @Scheduled(cron = "0 0 0 1 * *") + public void sendMonthlyPayments() { + triggerPayment(); + } + + // ✅ Separate method — call this for immediate testing + public void triggerPayment() { + + LocalDate today = LocalDate.now(); + +// ✅ Current month ka data — testing ke liye + LocalDate firstDay = today.withDayOfMonth(1); // Mar 1, 2026 + LocalDate lastDay = today; // Mar 11, 2026 (aaj) + + String periodStart = firstDay.format(DateTimeFormatter.ISO_DATE); + String periodEnd = lastDay.format(DateTimeFormatter.ISO_DATE); + + Timestamp startTs = Timestamp.valueOf(firstDay.atStartOfDay()); // 2026-03-01 00:00:00 + Timestamp endTs = Timestamp.valueOf(lastDay.plusDays(1).atStartOfDay()); // 2026-03-12 00:00:00 + + log.info("========================================"); + log.info("UTP Rerona Payment Job Started"); + log.info("Period: {} to {}", periodStart, periodEnd); + log.info("Start Timestamp: {}", startTs); + log.info("End Timestamp: {}", endTs); + log.info("========================================"); + + List allAshaIds = recordRepo.findDistinctAshaIdsByDateRange(startTs, endTs); + log.info("Total ASHAs found: {}", allAshaIds.size()); + + int success = 0, failed = 0, skipped = 0; + + for (Integer ashaId : allAshaIds) { + try { + log.info("----------------------------------------"); + log.info("Processing ASHA ID: {}", ashaId); + + // Fetch claimed and approved records for this ASHA + List entities = recordRepo + .findClaimedApprovedRecordsByAshaAndDateRange(ashaId, startTs, endTs); + + if (entities == null || entities.isEmpty()) { + log.warn("ASHA {} — No records found, skipping", ashaId); + skipped++; + continue; + } + + log.info("ASHA {} — Total records fetched: {}", ashaId, entities.size()); + + // Collect all unique activity IDs + Set activityIds = entities.stream() + .filter(e -> e.getActivityId() != null) + .map(IncentiveActivityRecord::getActivityId) + .collect(Collectors.toSet()); + + log.info("ASHA {} — Unique activity IDs: {}", ashaId, activityIds); + + // Fetch activity master data for all activity IDs at once + Map activityMap = incentivesRepo.findAllById(activityIds) + .stream() + .filter(a -> a.getIsDeleted() == null || !a.getIsDeleted()) + .collect(Collectors.toMap(IncentiveActivity::getId, a -> a)); + + // Group records by activity ID + Map> groupedByActivity = entities.stream() + .filter(e -> e.getActivityId() != null) + .collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); + + // Build items list from grouped records + List items = new ArrayList<>(); + + for (Map.Entry> entry : groupedByActivity.entrySet()) { + Long activityId = entry.getKey(); + List records = entry.getValue(); + + IncentiveActivity activity = activityMap.get(activityId); + if (activity == null) { + log.warn("ASHA {} — Activity ID {} not found in master, skipping", ashaId, activityId); + continue; + } + + // Calculate total incentive amount for this activity + Long totalAmount = records.stream() + .mapToLong(r -> r.getAmount() != null ? r.getAmount() : 0L) + .sum(); + + + String stateActivityCode = activity.getStateActivityCode() != null + ? String.valueOf(activity.getStateActivityCode()) + : null; + + if (stateActivityCode == null) { + log.warn("ASHA {} — ActivityId {} stateActivityCode null, skipping", ashaId, activityId); + continue; // ✅ Is item ko request mein add hi mat karo + } + + PaymentItem item = new PaymentItem(); + item.setActivityCode(stateActivityCode); + item.setCount(String.valueOf(records.size())); + item.setIncentiveAmount(String.valueOf(totalAmount)); + items.add(item); + + + + log.info("ASHA {} — Activity: {} | Count: {} | Total Amount: {}", + ashaId, activityId, records.size(), totalAmount); + } + + if (items.isEmpty()) { + log.warn("ASHA {} — No valid items found, skipping", ashaId); + skipped++; + continue; + } + + // Get verified by details from first record + IncentiveActivityRecord firstRecord = entities.get(0); + VerifiedBy verifiedBy = new VerifiedBy(); + verifiedBy.setEmployeeId(firstRecord.getVerifiedByUserId() != null + ? String.valueOf(firstRecord.getVerifiedByUserId()) : ""); + verifiedBy.setName(firstRecord.getVerifiedByUserName() != null + ? firstRecord.getVerifiedByUserName() : ""); + + // Build period object + Period period = new Period(); + period.setStart(periodStart); + period.setEnd(periodEnd); + + // Build final payment request + PaymentRequest paymentRequest = new PaymentRequest( + UUID.randomUUID().toString(), + "AMRIT", + period, + ashaId.toString(), + OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), + verifiedBy, + items + ); + + // Log full request before sending + log.info("ASHA {} — Request Payload: {}", ashaId, new Gson().toJson(paymentRequest)); + + // Send payment request to API + paymentService.sendPaymentRequest(paymentRequest); + + log.info("ASHA {} — Payment sent successfully", ashaId); + success++; + + } catch (Exception e) { + log.error("ASHA {} — Payment failed: {}", ashaId, e.getMessage(), e); + failed++; + } + } + + log.info("========================================"); + log.info("Job Complete | Success: {} | Failed: {} | Skipped: {}", success, failed, skipped); + log.info("========================================"); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/UpdateIncentivePendindDocService.java b/src/main/java/com/iemr/flw/service/impl/UpdateIncentivePendindDocService.java new file mode 100644 index 000000000..bfda259f4 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/UpdateIncentivePendindDocService.java @@ -0,0 +1,48 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.domain.iemr.IncentivePendingActivity; +import com.iemr.flw.repo.iemr.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class UpdateIncentivePendindDocService { + @Autowired + private IncentivesRepo incentivesRepo; + + @Autowired + private UserServiceRoleRepo userRepo; + + @Autowired + private IncentiveRecordRepo recordRepo; + + @Autowired + private IncentivePendingActivityRepository incentivePendingActivityRepository; + + public void updateIncentive(Long id) { + + Optional optionalRecord = recordRepo.findById(id); + + if (optionalRecord.isPresent()) { + IncentiveActivityRecord record = optionalRecord.get(); + record.setIsEligible(true); + recordRepo.save(record); + } + } + + public void updatePendingActivity(Integer userId, Long recordId, Long activityId, Long mIncentiveId) { + IncentivePendingActivity incentivePendingActivity = new IncentivePendingActivity(); + incentivePendingActivity.setActivityId(activityId); + incentivePendingActivity.setRecordId(recordId); + incentivePendingActivity.setUserId(userId); + incentivePendingActivity.setMincentiveId(mIncentiveId); + if (incentivePendingActivity != null) { + incentivePendingActivityRepository.save(incentivePendingActivity); + } + + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java index 4e680a1df..60ae973e7 100644 --- a/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java @@ -12,12 +12,17 @@ public class UserServiceImpl implements UserService { private final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); + @Autowired private UserServiceRoleRepo userServiceRoleRepo; + @Autowired + private FacilityDataService facilityDataService; + public UserServiceRoleDTO getUserDetail(Integer userId) { logger.info("calling getUserRole for userId: " + userId); UserServiceRoleDTO userRole = userServiceRoleRepo.getUserRole(userId).get(0); + userRole.setFacilityData(facilityDataService.buildFacilityData(userId, userRole.getRoleName())); return userRole; } } diff --git a/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java b/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java new file mode 100644 index 000000000..f0e5a5544 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java @@ -0,0 +1,66 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.dto.iemr.PaymentRequest; +import io.swagger.v3.oas.models.responses.ApiResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +@Service +public class UtpreronaPaymentIntegrationImpl { +// @Value("${ssdPortalUrl}") + private String API_URL = "https://nhmssd.assam.gov.in/APPMS_2024_25/api/utpreronaPayment.php"; + private String API_KEY = "41202fa384eab2725a17bbac58cf708bf04cd1dd5175010941606156dc36d6b5"; + private static final int TIMEOUT_SECONDS = 30; + + private final HttpClient httpClient; + private final ObjectMapper objectMapper; + + public UtpreronaPaymentIntegrationImpl() { + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(TIMEOUT_SECONDS)) + .build(); + this.objectMapper = new ObjectMapper(); + } + + public ApiResponse sendPaymentRequest(PaymentRequest paymentRequest) + throws IOException, InterruptedException { + + String jsonBody = objectMapper.writeValueAsString(paymentRequest); + System.out.println("Sending Request:"); + System.out.println(objectMapper.writerWithDefaultPrettyPrinter() + .writeValueAsString(paymentRequest)); + + HttpRequest httpRequest = HttpRequest.newBuilder() + .uri(URI.create(API_URL)) + .timeout(Duration.ofSeconds(TIMEOUT_SECONDS)) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .header("x-api-key", API_KEY) + .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) + .build(); + + HttpResponse httpResponse = httpClient.send( + httpRequest, + HttpResponse.BodyHandlers.ofString() + ); + + System.out.println("Response Status: " + httpResponse.statusCode()); + System.out.println("Response Body: " + httpResponse.body()); + + if (httpResponse.statusCode() == 200) { + return objectMapper.readValue(httpResponse.body(), ApiResponse.class); + } else { + throw new IOException("API Error - Status: " + httpResponse.statusCode() + + " | Body: " + httpResponse.body()); + } + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/UwinSessionServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/UwinSessionServiceImpl.java index bb2a944c9..d91d0c6f8 100644 --- a/src/main/java/com/iemr/flw/service/impl/UwinSessionServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/UwinSessionServiceImpl.java @@ -8,6 +8,7 @@ import com.iemr.flw.dto.iemr.UwinSessionRequestDTO; import com.iemr.flw.dto.iemr.UwinSessionResponseDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.iemr.IncentiveRecordRepo; import com.iemr.flw.repo.iemr.IncentivesRepo; import com.iemr.flw.repo.iemr.UserServiceRoleRepo; @@ -40,6 +41,9 @@ public class UwinSessionServiceImpl implements UwinSessionService { @Autowired private IncentiveRecordRepo recordRepo; + @Autowired + private UpdateIncentivePendindDocService updateIncentivePendindDocService; + @Override public UwinSessionResponseDTO saveSession(UwinSessionRequestDTO req) throws Exception { @@ -72,6 +76,7 @@ public UwinSessionResponseDTO saveSession(UwinSessionRequestDTO req) throws Exce session.setAshaId(req.getAshaId()); session.setDate(req.getDate()); session.setPlace(req.getPlace()); + session.setSessionDate(req.getDate()); session.setParticipants(req.getParticipants()); session.setCreatedBy(req.getCreatedBy()); if (req.getAttachments() != null && req.getAttachments().length > 0) { @@ -102,8 +107,45 @@ public UwinSessionResponseDTO saveSession(UwinSessionRequestDTO req) throws Exce dto.setParticipants(session.getParticipants()); dto.setAttachments(Collections.singletonList(session.getAttachmentsJson())); + return dto; } + @Override + public UwinSession updateSession(UwinSessionRequestDTO req, Long recordId, Long activityId) throws Exception { + Optional optionalUwinSession = repo.findById(recordId); + + if (optionalUwinSession.isPresent()) { + UwinSession session = optionalUwinSession.get(); // ✅ Use existing session + + // Update fields if present in request + if (req.getPlace() != null) session.setPlace(req.getPlace()); + if (req.getParticipants() != null) session.setParticipants(req.getParticipants()); + if (req.getDate() != null) session.setDate(req.getDate()); + + // Update attachments if present + if (req.getAttachments() != null && req.getAttachments().length > 0) { + List base64Images = Arrays.stream(req.getAttachments()) + .filter(file -> !file.isEmpty()) + .map(file -> { + try { + return Base64.getEncoder().encodeToString(file.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Error converting image to Base64", e); + } + }) + .collect(Collectors.toList()); + + String imagesJson = objectMapper.writeValueAsString(base64Images); + session.setAttachmentsJson(imagesJson); + + } + + repo.save(session); // ✅ Save updated session + return session; + } else { + throw new RuntimeException("Session not found for id: " + recordId); + } + } @Override public List getSessionsByAsha(Integer ashaId) throws Exception { @@ -130,9 +172,9 @@ public List getSessionsByAsha(Integer ashaId) throws Exc private void checkAndAddIncentive(UwinSession session) { IncentiveActivity incentiveActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_MOBILIZATION_SESSIONS", GroupName.IMMUNIZATION.getDisplayName()); IncentiveActivity incentiveActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_MOBILIZATION_SESSIONS", GroupName.ACTIVITY.getDisplayName()); + Integer stateId = userRepo.getUserRole(session.getAshaId()).get(0).getStateId(); - - if(incentiveActivityAM!=null){ + if(incentiveActivityAM!=null && stateId!=null && stateId.equals(StateCode.AM.getStateCode())){ IncentiveActivityRecord record = recordRepo .findRecordByActivityIdCreatedDateBenId(incentiveActivityAM.getId(), session.getDate(), 0L,session.getAshaId()); if (record == null) { @@ -147,11 +189,27 @@ record = new IncentiveActivityRecord(); record.setBenId(0L); record.setAshaId(session.getAshaId()); record.setAmount(Long.valueOf(incentiveActivityAM.getRate())); + record.setIsEligible(true); recordRepo.save(record); + + +// if(session.getAttachmentsJson()!=null){ +// record.setIsEligible(true); +// recordRepo.save(record); +// +// }else { +// record.setIsEligible(false); +// IncentiveActivityRecord incentiveActivityRecord = recordRepo.save(record); +// if(incentiveActivityRecord!=null){ +// updateIncentivePendindDocService.updatePendingActivity(session.getAshaId(),session.getId(),incentiveActivityRecord.getId(),incentiveActivityAM.getId()); +// +// } +// } + } } - if(incentiveActivityCH!=null){ + if(incentiveActivityCH!=null && stateId!=null && stateId.equals(StateCode.CG.getStateCode())){ IncentiveActivityRecord record = recordRepo .findRecordByActivityIdCreatedDateBenId(incentiveActivityCH.getId(), session.getDate(), 0L,session.getAshaId()); if (record == null) { @@ -166,6 +224,14 @@ record = new IncentiveActivityRecord(); record.setBenId(0L); record.setAshaId(session.getAshaId()); record.setAmount(Long.valueOf(incentiveActivityCH.getRate())); + record.setIsEligible(true); + +// if(session.getAttachmentsJson()!=null){ +// record.setIsEligible(true); +// }else { +// record.setIsEligible(false); +// updateIncentivePendindDocService.updatePendingActivity(session.getAshaId(),session.getId(),record.getId(),incentiveActivityCH.getId()); +// } recordRepo.save(record); } } diff --git a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java index 71bbdbad8..7f1104d1d 100644 --- a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java @@ -24,11 +24,11 @@ */ package com.iemr.flw.service.impl; -import com.iemr.flw.controller.CoupleController; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.VillageLevelFormService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,8 +37,10 @@ import java.sql.Timestamp; import java.time.LocalDate; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -70,6 +72,9 @@ public class VillageLevelFormServiceImpl implements VillageLevelFormService { @Autowired private AHDFormRepo ahdFormRepo; + @Autowired + private IncentiveLogicService incentiveLogicService; + @Override public Boolean saveForm(VhndDto dto) { @@ -132,11 +137,20 @@ private Boolean saveVhncFormData(VhncFormDTO vhncFormDTO, Integer userID) { vhncForm.setImage2(vhncFormDTO.getImage2()); vhncForm.setImage1(vhncFormDTO.getImage1()); vhncForm.setPlace(vhncFormDTO.getPlace()); + vhncForm.setVillageName(vhncFormDTO.getVillageName()); + vhncForm.setAnm(vhncFormDTO.getAnm()); + vhncForm.setAww(vhncFormDTO.getAww()); + vhncForm.setNoOfPragnentWoment(vhncFormDTO.getNoOfPragnentWoment()); + vhncForm.setNoOfLactingMother(vhncFormDTO.getNoOfLactingMother()); + vhncForm.setNoOfCommittee(vhncFormDTO.getNoOfCommittee()); + vhncForm.setFollowupPrevius(vhncFormDTO.getFollowupPrevius()); + vhncForm.setNoOfBeneficiariesAttended(vhncFormDTO.getNoOfBeneficiariesAttended()); vhncForm.setFormType("VHNC"); vhncFormRepo.save(vhncForm); - checkAndAddIncentives(vhncForm.getVhncDate(), Math.toIntExact(vhncForm.getUserId()), "VHSNC_MEETING", vhncForm.getCreatedBy()); + + checkVhncIncentive(vhncForm.getCreatedDate(),Math.toIntExact(vhncForm.getUserId())); return true; } @@ -149,10 +163,15 @@ private Boolean savePhcForm(PhcReviewMeetingFormDTO dto, Integer userID) { phcReviewForm.setPlace(dto.getPlace()); phcReviewForm.setNoOfBeneficiariesAttended(dto.getNoOfBeneficiariesAttended()); phcReviewForm.setImage1(dto.getImage1()); + phcReviewForm.setVillageName(dto.getVillageName()); + phcReviewForm.setMitaninActivityCheckList(dto.getMitaninActivityCheckList()); + phcReviewForm.setPlaceId(dto.getPlaceId()); + phcReviewForm.setMitaninHistory(dto.getMitaninHistory()); phcReviewForm.setImage2(dto.getImage2()); phcReviewForm.setFormType("PHC"); phcReviewFormRepo.save(phcReviewForm); - checkAndAddIncentives(phcReviewForm.getPhcReviewDate(), Math.toIntExact(phcReviewForm.getUserId()), "CLUSTER_MEETING", phcReviewForm.getCreatedBy()); + + checkPhcMeetingIncentive(phcReviewForm.getCreatedDate(),Math.toIntExact(phcReviewForm.getUserId())); return true; } @@ -198,18 +217,182 @@ private Boolean saveVhndFormData(VHNDFormDTO vhndFormDTO, Integer userID) { VHNDForm vhndForm = new VHNDForm(); vhndForm.setUserId(userID); vhndForm.setVhndDate(vhndFormDTO.getVhndDate()); - vhndForm.setImage2(vhndFormDTO.getImage2()); - vhndForm.setImage1(vhndFormDTO.getImage1()); - vhndForm.setPlace(vhndFormDTO.getPlace()); - vhndForm.setNoOfBeneficiariesAttended(vhndFormDTO.getNoOfBeneficiariesAttended()); + vhndForm.setImage2(vhndFormDTO.getImage2() != null ? vhndFormDTO.getImage2() : ""); + vhndForm.setImage1(vhndFormDTO.getImage1() != null ? vhndFormDTO.getImage1() : ""); + vhndForm.setPlace(vhndFormDTO.getPlace() != null ? vhndFormDTO.getPlace() : ""); + + vhndForm.setNoOfBeneficiariesAttended( + vhndFormDTO.getNoOfBeneficiariesAttended() != null + ? vhndFormDTO.getNoOfBeneficiariesAttended() + : 0); + + vhndForm.setPregnantWomenAnc( + vhndFormDTO.getPregnantWomenAnc() != null + ? vhndFormDTO.getPregnantWomenAnc() + : null); + + vhndForm.setLactatingMothersPnc( + vhndFormDTO.getLactatingMothersPnc() != null + ? vhndFormDTO.getLactatingMothersPnc() + : null); + + vhndForm.setChildrenImmunization( + vhndFormDTO.getChildrenImmunization() != null + ? vhndFormDTO.getChildrenImmunization() + : null); + + vhndForm.setSelectAllEducation( + vhndFormDTO.getSelectAllEducation() != null + ? vhndFormDTO.getSelectAllEducation() + : false); + + vhndForm.setKnowledgeBalancedDiet( + vhndFormDTO.getKnowledgeBalancedDiet() != null + ? vhndFormDTO.getKnowledgeBalancedDiet() + : null); + + vhndForm.setCareDuringPregnancy( + vhndFormDTO.getCareDuringPregnancy() != null + ? vhndFormDTO.getCareDuringPregnancy() + : null); + + vhndForm.setImportanceBreastfeeding( + vhndFormDTO.getImportanceBreastfeeding() != null + ? vhndFormDTO.getImportanceBreastfeeding() + : null); + + vhndForm.setComplementaryFeeding( + vhndFormDTO.getComplementaryFeeding() != null + ? vhndFormDTO.getComplementaryFeeding() + : null); + + vhndForm.setHygieneSanitation( + vhndFormDTO.getHygieneSanitation() != null + ? vhndFormDTO.getHygieneSanitation() + : null); + + vhndForm.setFamilyPlanningHealthcare( + vhndFormDTO.getFamilyPlanningHealthcare() != null + ? vhndFormDTO.getFamilyPlanningHealthcare() + : null); vhndForm.setFormType("VHND"); vhndRepo.save(vhndForm); - checkAndAddIncentives(vhndForm.getVhndDate(), vhndForm.getUserId(), "VHND_PARTICIPATION", vhndForm.getCreatedBy()); + + + checkVhndIncentive(vhndForm.getCreatedDate(),vhndForm.getUserId()); + return true; } + private void checkVhndIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("VHND_PARTICIPATION", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + + private void checkPhcMeetingIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("CLUSTER_MEETING", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + + + private void checkVhncIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("VHSNC_MEETING", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + + @Override public List getAll(GetVillageLevelRequestHandler getVillageLevelRequestHandler) { if (Objects.equals(getVillageLevelRequestHandler.getFormType(), "VHND")) { @@ -244,6 +427,8 @@ public List getAll(GetVillageLevelRequestHandler getVillageLev private void checkAndAddIncentives(String date, Integer userID, String formType, String createdBY) { + String userName = userRepo.getUserNamedByUserId(userID); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); // Parse to LocalDate @@ -265,11 +450,11 @@ private void checkAndAddIncentives(String date, Integer userID, String formType, record = new IncentiveActivityRecord(); record.setActivityId(villageFormEntryActivityAM.getId()); record.setCreatedDate(timestamp); - record.setCreatedBy(userRepo.getUserNamedByUserId(userID)); + record.setCreatedBy(userName); record.setStartDate(timestamp); record.setEndDate(timestamp); record.setUpdatedDate(timestamp); - record.setUpdatedBy(userRepo.getUserNamedByUserId(userID)); + record.setUpdatedBy(userName); record.setAshaId(userID); record.setBenId(0L); record.setAmount(Long.valueOf(villageFormEntryActivityAM.getRate())); @@ -277,7 +462,6 @@ record = new IncentiveActivityRecord(); } } - if (villageFormEntryActivityCH != null) { IncentiveActivityRecord record = recordRepo .findRecordByActivityIdCreatedDateBenId(villageFormEntryActivityCH.getId(), timestamp, 0L,userID); @@ -285,12 +469,12 @@ record = new IncentiveActivityRecord(); record = new IncentiveActivityRecord(); record.setActivityId(villageFormEntryActivityCH.getId()); record.setCreatedDate(timestamp); - record.setCreatedBy(userRepo.getUserNamedByUserId(userID)); + record.setCreatedBy(userName); record.setStartDate(timestamp); record.setEndDate(timestamp); record.setBenId(0L); record.setUpdatedDate(timestamp); - record.setUpdatedBy(userRepo.getUserNamedByUserId(userID)); + record.setUpdatedBy(userName); record.setAshaId(userID); record.setAmount(Long.valueOf(villageFormEntryActivityCH.getRate())); recordRepo.save(record); diff --git a/src/main/java/com/iemr/flw/utils/JwtAuthenticationUtil.java b/src/main/java/com/iemr/flw/utils/JwtAuthenticationUtil.java index 9144ca3be..c44c41da0 100644 --- a/src/main/java/com/iemr/flw/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/flw/utils/JwtAuthenticationUtil.java @@ -11,7 +11,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.repo.iemr.EmployeeMasterRepo; import com.iemr.flw.utils.exception.IEMRException; @@ -75,25 +75,25 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { String userId = claims.get("userId", String.class); // Check if user data is present in Redis - M_User user = getUserFromCache(userId); + User user = getUserFromCache(userId); if (user == null) { // If not in Redis, fetch from DB and cache the result user = fetchUserFromDB(userId); } if (user == null) { - throw new IEMRException("Invalid User ID."); + throw new IEMRException("Invalid User ID or user is deactivated please contact to admin."); } return true; // Valid userId and JWT token } catch (Exception e) { logger.error("Validation failed: " + e.getMessage(), e); - throw new IEMRException("Validation error: " + e.getMessage(), e); + throw new IEMRException("Validation error: Authentication failed", e); } } - private M_User getUserFromCache(String userId) { + private User getUserFromCache(String userId) { String redisKey = "user_" + userId; // The Redis key format - M_User user = (M_User) redisTemplate.opsForValue().get(redisKey); + User user = (User) redisTemplate.opsForValue().get(redisKey); if (user == null) { logger.warn("User not found in Redis. Will try to fetch from DB."); @@ -104,15 +104,15 @@ private M_User getUserFromCache(String userId) { return user; // Returns null if not found } - private M_User fetchUserFromDB(String userId) { + private User fetchUserFromDB(String userId) { // This method will only be called if the user is not found in Redis. String redisKey = "user_" + userId; // Redis key format // Fetch user from DB - M_User user = userLoginRepo.getUserByUserID(Integer.parseInt(userId)); + User user = userLoginRepo.findUserByUserID(Integer.parseInt(userId)); if (user != null) { - M_User userHash = new M_User(); + User userHash = new User(); userHash.setUserID(user.getUserID()); userHash.setUserName(user.getUserName()); diff --git a/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java index fcefd7127..9cf022f03 100644 --- a/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java @@ -116,7 +116,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo } catch (Exception e) { logger.error("Authorization error: ", e); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: Authentication failed"); } } @@ -152,7 +152,9 @@ private boolean shouldSkipPath(String path, String contextPath) { return path.equals(contextPath + "/user/userAuthenticate") || path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession") || path.startsWith(contextPath + "/swagger-ui") || path.startsWith(contextPath + "/v3/api-docs") - || path.startsWith(contextPath + "/public"); + || path.startsWith(contextPath + "/public") + || path.equals(contextPath + "/health") + || path.equals(contextPath + "/version"); } private String getJwtTokenFromCookies(HttpServletRequest request) { diff --git a/src/main/java/com/iemr/flw/utils/JwtUtil.java b/src/main/java/com/iemr/flw/utils/JwtUtil.java index 7107d7387..ab15e4647 100644 --- a/src/main/java/com/iemr/flw/utils/JwtUtil.java +++ b/src/main/java/com/iemr/flw/utils/JwtUtil.java @@ -90,13 +90,4 @@ private Claims extractAllClaims(String token) { .getPayload(); } - public String getUserNameFromStorage() { - return userName; - - } - - public void setUserNameFromStorage(String loginUserName) { - this.userName = loginUserName; - - } } diff --git a/src/main/java/com/iemr/flw/utils/LocalDateAdapter.java b/src/main/java/com/iemr/flw/utils/LocalDateAdapter.java new file mode 100644 index 000000000..d0081c299 --- /dev/null +++ b/src/main/java/com/iemr/flw/utils/LocalDateAdapter.java @@ -0,0 +1,20 @@ +package com.iemr.flw.utils; + +import com.google.gson.*; +import java.lang.reflect.Type; +import java.time.LocalDate; + +public class LocalDateAdapter + implements JsonSerializer, JsonDeserializer { + + @Override + public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.toString()); // yyyy-MM-dd + } + + @Override + public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + return LocalDate.parse(json.getAsString()); + } +} diff --git a/src/main/java/com/iemr/flw/utils/PathTraversalFilter.java b/src/main/java/com/iemr/flw/utils/PathTraversalFilter.java new file mode 100644 index 000000000..e63012bc0 --- /dev/null +++ b/src/main/java/com/iemr/flw/utils/PathTraversalFilter.java @@ -0,0 +1,56 @@ +package com.iemr.flw.utils; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; + +@Component +@Order(1) +public class PathTraversalFilter implements Filter { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) + throws IOException, ServletException { + + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + String uri = request.getRequestURI(); + + // Decode once to catch %2e%2e and similar encoded variants + String decodedUri = URLDecoder.decode(uri, StandardCharsets.UTF_8); + + if (containsTraversalPattern(uri) || containsTraversalPattern(decodedUri)) { + logger.warn("Path traversal attempt blocked: {}", uri); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid request path"); + return; + } + + chain.doFilter(servletRequest, servletResponse); + } + + private boolean containsTraversalPattern(String path) { + if (path == null) return false; + String normalized = path.toLowerCase(); + return normalized.contains("../") + || normalized.contains("..\\") + || normalized.contains("..;") + || normalized.contains("%2e%2e") + || normalized.contains("%252e") // double-encoded + || normalized.endsWith(".."); + } +} diff --git a/src/main/java/com/iemr/flw/utils/http/HTTPRequestInterceptor.java b/src/main/java/com/iemr/flw/utils/http/HTTPRequestInterceptor.java index 884d9905f..5c5aaf234 100644 --- a/src/main/java/com/iemr/flw/utils/http/HTTPRequestInterceptor.java +++ b/src/main/java/com/iemr/flw/utils/http/HTTPRequestInterceptor.java @@ -93,7 +93,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons if (remoteAddress == null || remoteAddress.trim().length() == 0) { remoteAddress = request.getRemoteAddr(); } -// validator.checkKeyExists(authorization, remoteAddress); + validator.checkKeyExists(authorization, remoteAddress); break; } } catch (Exception e) { diff --git a/src/main/java/com/iemr/flw/utils/redis/RedisConfig.java b/src/main/java/com/iemr/flw/utils/redis/RedisConfig.java index 0a2793198..98acde7ac 100644 --- a/src/main/java/com/iemr/flw/utils/redis/RedisConfig.java +++ b/src/main/java/com/iemr/flw/utils/redis/RedisConfig.java @@ -7,7 +7,7 @@ import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; @Configuration public class RedisConfig { @@ -20,7 +20,7 @@ public RedisTemplate redisTemplate(RedisConnectionFactory factor template.setKeySerializer(new StringRedisSerializer()); // Use Jackson2JsonRedisSerializer for values (Users objects) - Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(M_User.class); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(User.class); template.setValueSerializer(serializer); return template; diff --git a/src/main/java/com/iemr/flw/utils/sessionobject/SessionObject.java b/src/main/java/com/iemr/flw/utils/sessionobject/SessionObject.java index d84a1684b..c18da8203 100644 --- a/src/main/java/com/iemr/flw/utils/sessionobject/SessionObject.java +++ b/src/main/java/com/iemr/flw/utils/sessionobject/SessionObject.java @@ -81,7 +81,6 @@ private void updateConcurrentSessionObject(String key, String value, Boolean ext JsonElement jsnElmnt = jsnParser.parse(value); jsnOBJ = jsnElmnt.getAsJsonObject(); if (jsnOBJ.has("userName") && jsnOBJ.get("userName") != null) { - jwtUtil.setUserNameFromStorage(jsnOBJ.get("userName").getAsString()); objectStore.updateObject(jsnOBJ.get("userName").getAsString().trim().toLowerCase(), key, extendExpirationTime, sessionExpiryTime); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8546550db..034fbcc4a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -65,9 +65,10 @@ fhir-url= tm-url= springdoc.api-docs.enabled=true springdoc.swagger-ui.enabled=true + spring.redis.host=localhost spring.main.allow-bean-definition-overriding=true spring.redis.password= spring.redis.port=6379 -notificationurl=https://uatamrit.piramalswasthya.org/common-api/firebaseNotification/sendNotification \ No newline at end of file +notificationurl=https://uatamrit.piramalswasthya.org/common-api/firebaseNotification/sendNotification From 3f0dd454955790f2b35f5e541c86953e6bbed650 Mon Sep 17 00:00:00 2001 From: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:58:53 +0530 Subject: [PATCH 010/237] Release 3.8.2 (#268) * fix pnc incentive * fix pnc incentive * fix pnc incentive * fix vhnd incentive incentive * fix vhnd incentive incentive * fix vhnd incentive error * fix vhnd incentive error * fix vhnd incentive error * fix vhnd incentive error * fix cluster meeting incentive error * fix cluster meeting incentive error * fix tb incentive * fix slide test incentive * Fix/pb mb incentive issue 3.8.2 (#271) * fix duplicate incentive issue * fix duplicate incentive issue * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix hbyc incentive logic * fix hbyc incentive logic * fix hbyc incentive logic * optmiz query for incentive logic for hbnc * optmiz query for incentive logic for hbnc * fixed hbnc and leprosy incentive (#290) * fixed hbnc and leprosy incentive (#291) --- .../iemr/flw/domain/iemr/TBConfirmedCase.java | 1 + .../flw/repo/identity/BeneficiaryRepo.java | 2 +- .../repo/iemr/DiseaseLeprosyRepository.java | 2 + .../com/iemr/flw/repo/iemr/HbncVisitRepo.java | 5 +- .../flw/repo/iemr/IncentiveRecordRepo.java | 56 ++- .../repo/iemr/LeprosyFollowUpRepository.java | 2 +- .../iemr/flw/service/MaaMeetingService.java | 27 +- .../impl/AdolescentHealthServiceImpl.java | 4 +- .../flw/service/impl/CampaignServiceImpl.java | 8 +- .../service/impl/ChildCareServiceImpl.java | 252 ++++------- .../flw/service/impl/CoupleServiceImpl.java | 57 ++- .../service/impl/DeathReportsServiceImpl.java | 46 +- .../impl/DeliveryOutcomeServiceImpl.java | 237 +++++++--- .../impl/DiseaseControlServiceImpl.java | 224 ++++------ .../impl/IFAFormSubmissionServiceImpl.java | 2 +- .../flw/service/impl/IncentiveLogicImpl.java | 6 +- .../service/impl/IncentiveServiceImpl.java | 410 +++++++----------- .../flw/service/impl/InfantServiceImpl.java | 2 +- .../impl/MaternalHealthServiceImpl.java | 169 +++++--- .../impl/TBConfirmedCaseServiceImpl.java | 14 +- .../impl/VillageLevelFormServiceImpl.java | 124 +++++- 21 files changed, 849 insertions(+), 801 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java index adacdb1b8..8310eb65a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java @@ -70,4 +70,5 @@ public class TBConfirmedCase { @Column(name = "updated_at") private LocalDate updatedAt; + } diff --git a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java index b3988c3eb..e4ce22f04 100644 --- a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java +++ b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java @@ -26,7 +26,7 @@ public interface BeneficiaryRepo extends JpaRepository findById(Long benID); List findByHouseoldId(Long houseHoldId); - Optional findByBenficieryid(Long benID); + List findByBenficieryid(Long benID); @Query(value = "SELECT beneficiaryRegID FROM db_identity.i_beneficiarydetails_rmnch WHERE BeneficiaryId = :benId", nativeQuery = true) Long getBenRegIdFromBenId(@Param("benId") Long benId); diff --git a/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java b/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java index 567b62a53..36873319e 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java +++ b/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java @@ -16,4 +16,6 @@ public interface DiseaseLeprosyRepository extends JpaRepository getByCreatedBy(@Param("createdBy") String createdBy); + + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java index 655c05471..cbc7f568d 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java @@ -1,6 +1,8 @@ package com.iemr.flw.repo.iemr; import com.iemr.flw.domain.iemr.HbncVisit; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -20,6 +22,5 @@ public interface HbncVisitRepo extends JpaRepository { HbncVisit findByBeneficiaryIdAndVisit_day(@Param("beneficiaryId") Long beneficiaryId, @Param("visitDay") String visitDay); - List findByAshaId(Integer ashaId); - + Page findByAshaId(Integer ashaId, Pageable pageable); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 11710e4c1..8c21f0e9f 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -3,6 +3,8 @@ import com.iemr.flw.domain.iemr.IncentiveActivityRecord; import jakarta.persistence.Column; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -18,41 +20,51 @@ public interface IncentiveRecordRepo extends JpaRepository { @Query(value = """ - SELECT * - FROM db_iemr.incentive_activity_record r - WHERE r.activity_id = :id - AND r.ben_id = :benId - AND MONTH(r.created_date) = MONTH(:createdDate) - AND YEAR(r.created_date) = YEAR(:createdDate) - LIMIT 1 - """, nativeQuery = true) - IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId(@Param("id") Long id, @Param("createdDate") Timestamp createdDate, @Param("benId") Long benId); + SELECT * + FROM db_iemr.incentive_activity_record r + WHERE r.activity_id = :id + AND r.ben_id = :benId + AND r.asha_id = :ashaId + AND MONTH(r.start_date) = MONTH(:createdDate) + AND YEAR(r.start_date) = YEAR(:createdDate) + LIMIT 1 + """, nativeQuery = true) + IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId( + @Param("id") Long id, + @Param("createdDate") Timestamp createdDate, + @Param("benId") Long benId, + @Param("ashaId") Integer ashaId); Optional findById(Long id); - @Query("select record from IncentiveActivityRecord record where record.activityId = :id and record.createdDate = :createdDate and record.benId = :benId and record.ashaId = :ashaId") - IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId(@Param("id") Long id, @Param("createdDate") Timestamp createdDate, @Param("benId") Long benId, @Param("ashaId") Integer ashaId); - - - @Query("SELECT record FROM IncentiveActivityRecord record " + - "WHERE record.activityId = :id " + - "AND record.createdDate BETWEEN :startDate AND :endDate " + - "AND record.benId = :benId " + // ← space added here - "AND record.ashaId = :ashaId") + @Query(value = """ + SELECT * + FROM incentive_activity_record + WHERE activity_id = :activityId + AND ben_id = :benId + AND asha_id = :ashaId + AND created_date >= :startOfMonth + AND created_date < :startOfNextMonth + ORDER BY created_date DESC + LIMIT 1 + """, nativeQuery = true) IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId( - @Param("id") Long id, - @Param("startDate") Timestamp startDate, - @Param("endDate") Timestamp endDate, + @Param("activityId") Long activityId, @Param("benId") Long benId, - @Param("ashaId") Integer ashaId + @Param("ashaId") Integer ashaId, + @Param("startOfMonth") Timestamp startOfMonth, + @Param("startOfNextMonth") Timestamp startOfNextMonth ); @Query("select record from IncentiveActivityRecord record where record.ashaId = :ashaId and record.startDate >= :fromDate and record.startDate <= :toDate and record.endDate >= :fromDate and record.endDate <= :toDate ") List findRecordsByAsha(@Param("ashaId") Integer ashaId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query("SELECT DISTINCT record FROM IncentiveActivityRecord record WHERE record.ashaId = :ashaId") + Page findRecordsByAsha(@Param("ashaId") Integer ashaId, Pageable pageable); + @Query("SELECT DISTINCT record FROM IncentiveActivityRecord record WHERE record.ashaId = :ashaId") List findRecordsByAsha(@Param("ashaId") Integer ashaId); diff --git a/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java b/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java index 4227fb3a2..a2b38f555 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java +++ b/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java @@ -12,7 +12,7 @@ @Repository public interface LeprosyFollowUpRepository extends JpaRepository { - Optional findByBenId(Long benId); + List findByBenId(Long benId); // Custom queries can be added here if needed @Query("SELECT s FROM LeprosyFollowUp s WHERE s.createdBy = :createdBy") diff --git a/src/main/java/com/iemr/flw/service/MaaMeetingService.java b/src/main/java/com/iemr/flw/service/MaaMeetingService.java index d8fdd82b5..cfe6aa204 100644 --- a/src/main/java/com/iemr/flw/service/MaaMeetingService.java +++ b/src/main/java/com/iemr/flw/service/MaaMeetingService.java @@ -239,20 +239,23 @@ record = new IncentiveActivityRecord(); record.setBenId(0L); record.setAshaId(meeting.getAshaId()); record.setAmount(Long.valueOf(incentiveActivity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); - if (meeting.getMeetingImagesJson() != null) { - record.setIsEligible(true); - recordRepo.save(record); - - } else { - record.setIsEligible(false); - IncentiveActivityRecord activityRecord = recordRepo.save(record); - if (activityRecord != null) { - updatePendingActivity(meeting.getAshaId(), meeting.getId(), activityRecord.getId(), incentiveActivity.getId()); - - } - } +// if (meeting.getMeetingImagesJson() != null) { +// record.setIsEligible(true); +// recordRepo.save(record); +// +// } else { +// record.setIsEligible(false); +// IncentiveActivityRecord activityRecord = recordRepo.save(record); +// if (activityRecord != null) { +// updatePendingActivity(meeting.getAshaId(), meeting.getId(), activityRecord.getId(), incentiveActivity.getId()); +// +// } +// +// } } } diff --git a/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java index 43986a8c9..8be992afe 100644 --- a/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java @@ -126,7 +126,7 @@ private void checkAndAddIncentives(AdolescentHealth adolescentHealth) { if (sellingSanitaryActivity != null) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(sellingSanitaryActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(sellingSanitaryActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue(),adolescentHealth.getUserId()); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(sellingSanitaryActivity.getId()); @@ -151,7 +151,7 @@ record = new IncentiveActivityRecord(); if (mobilizingADHActivity != null) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(mobilizingADHActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(mobilizingADHActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue(),adolescentHealth.getUserId()); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(mobilizingADHActivity.getId()); diff --git a/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java index 1d1988d4e..f9c076327 100644 --- a/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java @@ -449,7 +449,7 @@ private List parseBase64Json(String jsonString) { private void checkMonthlyPulsePolioIncentive(Integer ashaId,LocalDate startDate,LocalDate endDate) { - IncentiveActivity CHILD_MOBILIZATION_SESSIONS = incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_MOBILIZATION_SESSIONS", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity CHILD_MOBILIZATION_SESSIONS = incentivesRepo.findIncentiveMasterByNameAndGroup("PULSE_POLIO_SUPPORT", GroupName.ACTIVITY.getDisplayName()); if (CHILD_MOBILIZATION_SESSIONS != null) { addAshaIncentiveRecord(CHILD_MOBILIZATION_SESSIONS, ashaId,startDate,endDate); } @@ -480,10 +480,10 @@ private void addAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( incentiveActivity.getId(), - startOfMonth, - endOfMonth, 0L, - ashaId + ashaId, + startOfMonth, + endOfMonth ); diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index f452916cf..e65e0f53e 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -21,6 +21,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -229,51 +233,62 @@ public List getHbycRecords(GetBenRequestHandler dto) { @Override public List getHBNCDetails(GetBenRequestHandler dto) { List result = new ArrayList<>(); + int page = 0; + int size = 20; + + Page visitPage; try { - List hbncVisits = hbncVisitRepo.findByAshaId(dto.getAshaId()); + do { + Pageable pageable = PageRequest.of(page, size, Sort.by("id").descending()); - for (HbncVisit visit : hbncVisits) { - HbncVisitResponseDTO responseDTO = new HbncVisitResponseDTO(); - responseDTO.setId(visit.getId()); - responseDTO.setBeneficiaryId(visit.getBeneficiaryId()); // Update with actual value - responseDTO.setHouseHoldId(visit.getHouseHoldId()); // Update with actual value - responseDTO.setVisitDate(visit.getVisit_date().split(" ")[0]); // Format visit.getVisitDate() + visitPage = hbncVisitRepo.findByAshaId(dto.getAshaId(), pageable); - // Convert all fields to Map - Map fields = new HashMap<>(); - if(visit.getVisit_day()!=null){ - addIfValid(fields, "visit_day", visit.getVisit_day()); + List hbncVisits = visitPage.getContent(); + + for (HbncVisit visit : hbncVisits) { + HbncVisitResponseDTO responseDTO = new HbncVisitResponseDTO(); + responseDTO.setId(visit.getId()); + responseDTO.setBeneficiaryId(visit.getBeneficiaryId()); // Update with actual value + responseDTO.setHouseHoldId(visit.getHouseHoldId()); // Update with actual value + responseDTO.setVisitDate(visit.getVisit_date().split(" ")[0]); // Format visit.getVisitDate() + + // Convert all fields to Map + Map fields = new HashMap<>(); + if(visit.getVisit_day()!=null){ + addIfValid(fields, "visit_day", visit.getVisit_day()); + + } + addIfValid(fields, "due_date", visit.getDue_date()); + addIfValid(fields, "is_baby_alive", convert(visit.getIs_baby_alive())); + addIfValid(fields, "date_of_death", visit.getDate_of_death()); + addIfValid(fields, "reason_for_death", visit.getReasonForDeath()); + addIfValid(fields, "place_of_death", visit.getPlace_of_death()); + addIfValid(fields, "other_place_of_death", visit.getOther_place_of_death()); + addIfValid(fields, "baby_weight", visit.getBaby_weight()); + addIfValid(fields, "urine_passed", convert(visit.getUrine_passed())); + addIfValid(fields, "stool_passed", convert(visit.getStool_passed())); + addIfValid(fields, "diarrhoea", convert(visit.getDiarrhoea())); + addIfValid(fields, "vomiting", convert(visit.getVomiting())); + addIfValid(fields, "convulsions", convert(visit.getConvulsions())); + addIfValid(fields, "activity", visit.getActivity()); + addIfValid(fields, "sucking", visit.getSucking()); + addIfValid(fields, "breathing", visit.getBreathing()); + addIfValid(fields, "chest_indrawing", visit.getChest_indrawing()); + addIfValid(fields, "temperature", visit.getTemperature()); + addIfValid(fields, "jaundice", convert(visit.getJaundice())); + addIfValid(fields, "umbilical_stump", visit.getUmbilical_stump()); + addIfValid(fields, "discharged_from_sncu", convert(visit.getDischarged_from_sncu())); + addIfValid(fields, "discharge_summary_upload", visit.getDischarge_summary_upload()); + + // Add more fields as required + + responseDTO.setFields(fields); + result.add(responseDTO); } - addIfValid(fields, "due_date", visit.getDue_date()); - addIfValid(fields, "is_baby_alive", convert(visit.getIs_baby_alive())); - addIfValid(fields, "date_of_death", visit.getDate_of_death()); - addIfValid(fields, "reason_for_death", visit.getReasonForDeath()); - addIfValid(fields, "place_of_death", visit.getPlace_of_death()); - addIfValid(fields, "other_place_of_death", visit.getOther_place_of_death()); - addIfValid(fields, "baby_weight", visit.getBaby_weight()); - addIfValid(fields, "urine_passed", convert(visit.getUrine_passed())); - addIfValid(fields, "stool_passed", convert(visit.getStool_passed())); - addIfValid(fields, "diarrhoea", convert(visit.getDiarrhoea())); - addIfValid(fields, "vomiting", convert(visit.getVomiting())); - addIfValid(fields, "convulsions", convert(visit.getConvulsions())); - addIfValid(fields, "activity", visit.getActivity()); - addIfValid(fields, "sucking", visit.getSucking()); - addIfValid(fields, "breathing", visit.getBreathing()); - addIfValid(fields, "chest_indrawing", visit.getChest_indrawing()); - addIfValid(fields, "temperature", visit.getTemperature()); - addIfValid(fields, "jaundice", convert(visit.getJaundice())); - addIfValid(fields, "umbilical_stump", visit.getUmbilical_stump()); - addIfValid(fields, "discharged_from_sncu", convert(visit.getDischarged_from_sncu())); - addIfValid(fields, "discharge_summary_upload", visit.getDischarge_summary_upload()); - - // Add more fields as required - - responseDTO.setFields(fields); - result.add(responseDTO); - checkAndAddHbncIncentives(hbncVisits, dto.getAshaId()); + page++; - } + }while (visitPage.hasNext()); } catch (Exception e) { logger.error("Error in getHBNCDetails: ", e); @@ -826,63 +841,64 @@ private void checkAndAddOrdDistributionIncentive(List orsDistri orsDistributionList.forEach(orsDistribution -> { IncentiveActivity orsPacketActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity orsPacketActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); if (orsPacketActivityAM != null) { if (orsDistribution.getNumOrsPackets() != null) { createIncentiveRecordforOrsDistribution(orsDistribution, orsDistribution.getBeneficiaryId(), orsPacketActivityAM, userRepo.getUserNamedByUserId(orsDistribution.getUserId()), false); } } - if (orsPacketActivityCH != null) { - if (orsDistribution.getNumOrsPackets() != null) { - createIncentiveRecordforOrsDistribution(orsDistribution, orsDistribution.getBeneficiaryId(), orsPacketActivityCH, userRepo.getUserNamedByUserId(orsDistribution.getUserId()), true); - } - } - }); } private void checkAndAddHbyncIncentives(List hbycList) { - IncentiveActivity hbync15MonethVisitActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity hbyncVisitActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.CHILD_HEALTH.getDisplayName()); + if(!hbycList.isEmpty()){ + Integer userId = hbycList.get(0).getUserId(); + Integer stateId = userService.getUserDetail(userId).getStateId(); + IncentiveActivity hbync15MonethVisitActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity hbyncVisitActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity hbyncOrsPacketActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); - hbycList.forEach(hbyc -> { - Set eligibleHbycVisits = Set.of("3 Months", "6 Months", "9 Months", "12 Months", "15 Months"); + IncentiveActivity hbyncLactatingIronPacketActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("LACTATING_MOTHERS_HOME_VISIT", GroupName.ACTIVITY.getDisplayName()); - if (hbyncVisitActivity != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { - createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncVisitActivity, hbyc.getCreated_by()); - } - - if (hbync15MonethVisitActivityCH != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { - createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbync15MonethVisitActivityCH, hbyc.getCreated_by()); - } + hbycList.forEach(hbyc -> { + Set eligibleHbycVisits = Set.of("3 Months", "6 Months", "9 Months", "12 Months", "15 Months"); + if(stateId.equals(StateCode.AM.getStateCode())){ + if (hbyncVisitActivity != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncVisitActivity, hbyc.getCreated_by()); + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ + if (hbync15MonethVisitActivityCH != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbync15MonethVisitActivityCH, hbyc.getCreated_by()); + } + if(hbyc.getIfa_given() && eligibleHbycVisits.contains(hbyc.getVisit_day())){ + if(hbyncLactatingIronPacketActivityCH!=null){ + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncLactatingIronPacketActivityCH, hbyc.getCreated_by()); - if (hbyncOrsPacketActivityCH != null) { - if (hbyc.getOrs_given()) { - createIncentiveRecordforHbyncOrsDistribution(hbyc, hbyc.getBeneficiaryId(), hbyncOrsPacketActivityCH, hbyc.getCreated_by()); + } + } } - } - }); + + + }); + } + } private void checkAndAddHbncIncentives(List hbncVisits, Integer userId) { Integer stateCode = userService.getUserDetail(userId).getStateId(); - List pncVisits = pncVisitRepo.getPNCForPW(userRepo.getUserNamedByUserId(userId)); - List ancVisits = ancVisitRepo.getANCForPW(userRepo.getUserNamedByUserId(userId)); hbncVisits.forEach(hbncVisit -> { Long benId = hbncVisit.getBeneficiaryId(); if (stateCode.equals(StateCode.AM.getStateCode())) { @@ -893,43 +909,7 @@ private void checkAndAddHbncIncentives(List hbncVisits, Integer userI } - pncVisits.forEach(pncVisit -> { - Long hbncHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(hbncVisit.getBeneficiaryId())).get(0).getHouseoldId(); - Long houseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(pncVisit.getBenId())).get(0).getHouseoldId(); - - if (hbncHouseHoldId.equals(houseHoldId)) { - if (hbncVisit.getVisit_day().equals("42th Day")) { - if (!ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { - if (ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getIsHrpConfirmed()) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, pncVisit.getBenId(), visitActivityCH, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); - } - } - if (!pncVisitRepo.findByBenId(pncVisit.getBenId()).isEmpty()) { - if (!pncVisitRepo.findByBenId(pncVisit.getBenId()).get(0).getMotherDangerSign().isEmpty()) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, pncVisit.getBenId(), visitActivityCH, "HIGH_RISK_POSTPARTUM_CARE"); - } - } - } - } - }); - - ancVisits.forEach(ancVisit -> { - Long hbncHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(hbncVisit.getBeneficiaryId())).get(0).getHouseoldId(); - Long ancHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(ancVisit.getBenId())).get(0).getHouseoldId(); - - if (hbncHouseHoldId.equals(ancHouseHoldId)) { - if (hbncVisit.getVisit_day().equals("42th Day")) { - if (!ancVisitRepo.findByBenId(ancVisit.getBenId()).isEmpty()) { - if (ancVisitRepo.findByBenId(ancVisit.getBenId()).get(0).getIsHrpConfirmed()) { - IncentiveActivity visitActivityANC = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, ancVisit.getBenId(), visitActivityANC, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); - } - } - } - } - }); + logger.info("getDischarged_from_sncu" + hbncVisit.getDischarged_from_sncu()); @@ -950,25 +930,10 @@ private void checkAndAddHbncIncentives(List hbncVisits, Integer userI } if (stateCode.equals(StateCode.CG.getStateCode())) { - if (hbncVisit.getVisit_day().equals("42th Day")) { - if (!ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { - if (ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getIsHrpConfirmed() && pncVisitRepo.findByBenId(hbncVisit - .getBeneficiaryId()).get(0).getPncPeriod().toString().equals("42")) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); - - createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); - - } - } - if (!pncVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { - if (!pncVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getMotherDangerSign().isEmpty() && pncVisitRepo.findByBenId(hbncVisit - .getBeneficiaryId()).get(0).getPncPeriod().toString().equals("42")) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); + if (hbncVisit.getVisit_day().equals("42nd Day")) { + IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.ACTIVITY.getDisplayName()); + createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HBNC_0_42_DAYS"); - createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HIGH_RISK_POSTPARTUM_CARE"); - - } - } } } @@ -1158,7 +1123,7 @@ private void checkAndAddIncentives(List vaccinationList) { private void createIncentiveRecord(ChildVaccination vaccination, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), vaccination.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), vaccination.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); @@ -1180,7 +1145,7 @@ private void createIncentiveRecordforHbncVisit(HbncVisit hbncVisit, Long benId, logger.info("RecordIncentive" + activityName); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), hbncVisit.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), hbncVisit.getCreatedDate(), benId,hbncVisit.getAshaId()); if (record == null) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); @@ -1267,7 +1232,7 @@ private void createIncentiveRecordforHbyncVisit(HbycChildVisit data, Long benId, // Convert LocalDate to Timestamp (00:00:00 by default) Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId,data.getUserId()); if (record == null) { @@ -1288,41 +1253,12 @@ record = new IncentiveActivityRecord(); } - private void createIncentiveRecordforHbyncOrsDistribution(HbycChildVisit data, Long benId, IncentiveActivity immunizationActivity, String createdBy) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); - - // Convert to LocalDate - LocalDate localDate = LocalDate.parse(data.getVisit_date(), formatter); - - // Convert LocalDate to Timestamp (00:00:00 by default) - Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); - - - if (record == null) { - - record = new IncentiveActivityRecord(); - record.setActivityId(immunizationActivity.getId()); - record.setCreatedDate(visitDate); - record.setCreatedBy(createdBy); - record.setStartDate(visitDate); - record.setEndDate(visitDate); - record.setUpdatedDate(visitDate); - record.setUpdatedBy(createdBy); - record.setBenId(benId); - record.setAshaId(data.getUserId()); - record.setAmount(Long.valueOf(immunizationActivity.getRate())); - recordRepo.save(record); - } - } - private void createIncentiveRecordforOrsDistribution(OrsDistribution data, Long benId, IncentiveActivity immunizationActivity, String createdBy, boolean isCH) { try { // Convert to LocalDate Timestamp visitDate = Timestamp.valueOf(data.getVisitDate().atStartOfDay()); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId,data.getUserId()); double packets = Double.parseDouble(data.getNumOrsPackets()); double rate = immunizationActivity.getRate(); @@ -1336,7 +1272,7 @@ record = new IncentiveActivityRecord(); record.setEndDate(visitDate); record.setUpdatedDate(visitDate); record.setUpdatedBy(createdBy); - record.setBenId(benId); + record.setBenId(0L); record.setAshaId(data.getUserId()); if (isCH) { record.setAmount((long) rate); @@ -1359,7 +1295,7 @@ private void createIncentiveRecordforSamReferalToNrc(SamVisit data, Long benId, // Convert to LocalDate Timestamp visitDate = Timestamp.valueOf(data.getVisitDate().atStartOfDay()); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), visitDate, benId); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), visitDate, benId,data.getUserId()); if (record == null) { diff --git a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java index e6aca951b..e22147afa 100644 --- a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java @@ -30,6 +30,7 @@ import java.util.Arrays; import java.util.Base64; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Service @@ -60,6 +61,8 @@ public class CoupleServiceImpl implements CoupleService { private BeneficiaryRepo beneficiaryRepo; private final Logger logger = LoggerFactory.getLogger(CoupleServiceImpl.class); + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + @Override @@ -259,7 +262,7 @@ private void checkIncentiveForChildGap(Integer stateId, String userName,List new Object()); + synchronized (lock){ + if (activity != null) { + Integer userId = userRepo.getUserIdByName(eligibleCoupleDTO.getCreatedBy()); + + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), eligibleCoupleDTO.getCreatedDate(), eligibleCoupleDTO.getBenId(),userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(eligibleCoupleDTO.getCreatedDate()); + record.setCreatedBy(eligibleCoupleDTO.getCreatedBy()); + record.setStartDate(eligibleCoupleDTO.getCreatedDate()); + record.setEndDate(eligibleCoupleDTO.getCreatedDate()); + record.setUpdatedDate(eligibleCoupleDTO.getCreatedDate()); + record.setUpdatedBy(eligibleCoupleDTO.getCreatedBy()); + record.setBenId(eligibleCoupleDTO.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(activity.getRate())); + recordRepo.save(record); + } } } + lockMap.remove(lockKey, lock); + + + } @Override @@ -572,7 +585,7 @@ private void checkAndAddAntaraIncentive(EligibleCoupleTracking ect) { private void addIncenticeRecord(EligibleCoupleTracking ect, Integer userId, IncentiveActivity antaraActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getCreatedDate(), ect.getBenId()); + .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getVisitDate(), ect.getBenId(),userId); // get bene details if (record == null) { diff --git a/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java index 2bd0ead83..b7eee7dd0 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java @@ -216,17 +216,21 @@ public List getMdsrRecords(GetBenRequestHandler dto) { } private void checkAndAddIncentives(List cdrList) { + if(!cdrList.isEmpty()){ + Integer userId = userRepo.getUserIdByName(cdrList.get(0).getCreatedBy()); + cdrList.forEach(cdr -> { + IncentiveActivity immunizationActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); + createIncentiveRecord(cdr, cdr.getBenId(), userId, immunizationActivity); + if(immunizationActivity!=null){ + createIncentiveRecord(cdr,cdr.getBenId(),userId,immunizationActivity); + + } + }); + + } - cdrList.forEach(cdr -> { - Integer userId = userRepo.getUserIdByName(cdr.getCreatedBy()); - IncentiveActivity immunizationActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); - createIncentiveRecord(cdr, cdr.getBenId(), userId, immunizationActivity); - if(immunizationActivity!=null){ - createIncentiveRecord(cdr,cdr.getBenId(),userId,immunizationActivity); - } - }); } @@ -263,7 +267,7 @@ private void checkAndAddIncentivesMdsr(List mdsrList) { private void createIncentiveRecord(CDR cdr, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), cdr.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), cdr.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(immunizationActivity.getId()); @@ -276,32 +280,16 @@ record = new IncentiveActivityRecord(); record.setBenId(benId); record.setAshaId(userId); record.setAmount(Long.valueOf(immunizationActivity.getRate())); - if (userRepo.getUserRole(userId).get(0).getStateId() == StateCode.AM.getStateCode()) { - if (cdr.getDeathCertImage1() != null && cdr.getCdrImage() != null && cdr.getCdrImage2() != null && cdr.getDeathCertImage2() != null) { - record.setIsEligible(true); - recordRepo.save(record); + record.setIsEligible(true); + recordRepo.save(record); - } else { - record.setIsEligible(false); - IncentiveActivityRecord incentiveActivityRecord = recordRepo.save(record); - if (incentiveActivityRecord == null) { - recordRepo.save(record); - pendindDocService.updatePendingActivity(userId, cdr.getId(), record.getId(), immunizationActivity.getId()); - - } - - } - } else { - recordRepo.save(record); - - } } } private void createIncentiveRecord(MDSR mdsr, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), mdsr.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), mdsr.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(immunizationActivity.getId()); diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index 3ccd99736..3170deba0 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -11,6 +11,7 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.DeliveryOutcomeDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.identity.HouseHoldRepo; import com.iemr.flw.repo.iemr.DeliveryOutcomeRepo; @@ -18,6 +19,7 @@ import com.iemr.flw.repo.iemr.IncentivesRepo; import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.DeliveryOutcomeService; +import com.iemr.flw.service.UserService; import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.Validate; import org.modelmapper.ModelMapper; @@ -27,6 +29,10 @@ import org.springframework.stereotype.Service; import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -51,6 +57,9 @@ public class DeliveryOutcomeServiceImpl implements DeliveryOutcomeService { @Autowired private UserServiceRoleRepo userRepo; + @Autowired + private UserService userService; + @Autowired private IncentiveRecordRepo recordRepo; @@ -122,85 +131,171 @@ public List getDeliveryOutcome(GetBenRequestHandler dto) { public void checkAndAddJsyIncentive(List delOutList) { + if(!delOutList.isEmpty()){ + Integer userID = userRepo.getUserIdByName(delOutList.get(0).getCreatedBy()); + Integer stateId = userService.getUserDetail(userID).getStateId(); + delOutList.forEach(deliveryOutcome -> { + + IncentiveActivity institutionalDeliveryActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MH_MOTIVATE_INST_DEL", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity institutionalDeliveryActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("INST_DELIVERY_ESCORT", GroupName.ACTIVITY.getDisplayName()); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + + if (placeOfDelivery != null && + (!placeOfDelivery.equalsIgnoreCase("home") || + !placeOfDelivery.equalsIgnoreCase("in transit") || + !placeOfDelivery.equalsIgnoreCase("other private hospital"))) { + + // Institutional delivery (eligible case) + if (institutionalDeliveryActivityAM != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityAM); + } - delOutList.forEach(deliveryOutcome -> { - - IncentiveActivity institutionalDeliveryActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MH_MOTIVATE_INST_DEL", GroupName.MATERNAL_HEALTH.getDisplayName()); - IncentiveActivity institutionalDeliveryActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("INST_DELIVERY_ESCORT", GroupName.ACTIVITY.getDisplayName()); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); - - if (placeOfDelivery != null && - (!placeOfDelivery.equalsIgnoreCase("home") || - !placeOfDelivery.equalsIgnoreCase("in transit") || - !placeOfDelivery.equalsIgnoreCase("other private hospital"))) { - - // Institutional delivery (eligible case) - if (institutionalDeliveryActivityAM != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityAM); + if (institutionalDeliveryActivityCH != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityCH); + } } + } - if (institutionalDeliveryActivityCH != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityCH); + if (deliveryOutcome.getIsJSYBenificiary()) { + IncentiveActivity incentiveActivityInstJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + + + logger.info("delOutList" + gson.toJson(deliveryOutcome)); + IncentiveActivity incentiveActivityJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY1 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 1) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); + } + } } - } - } - if (deliveryOutcome.getIsJSYBenificiary()) { - IncentiveActivity incentiveActivityInstJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY2 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 2) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY2); + if (deliveryOutcome.getPlaceOfDelivery() != null) { - logger.info("delOutList" + gson.toJson(deliveryOutcome)); - IncentiveActivity incentiveActivityJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY1 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 1) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); + } } } - } + IncentiveActivity incentiveActivityJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY3 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 3) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY3); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); + } + } + } - IncentiveActivity incentiveActivityJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY2 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 2) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY2); - if (deliveryOutcome.getPlaceOfDelivery() != null) { + IncentiveActivity incentiveActivityJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY4 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 4) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY4); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); + } } } + } + if(deliveryOutcome.getDeliveryOutcome()!=null){ + if(!beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).isEmpty()){ + RMNCHBeneficiaryDetailsRmnch rmnchBeneficiaryDetailsRmnch = beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).get(0); + LocalDate marriageDate = rmnchBeneficiaryDetailsRmnch.getDateMarriage() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate deliveryDate = deliveryOutcome.getDateOfDelivery() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + long years = ChronoUnit.YEARS.between(marriageDate, deliveryDate); + if (years >= 2 && !rmnchBeneficiaryDetailsRmnch.getDoYouHavechildren()) { + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.FAMILY_PLANNING.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + - IncentiveActivity incentiveActivityJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY3 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 3) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY3); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); } + } + + + } - IncentiveActivity incentiveActivityJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY4 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 4) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY4); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); + if(deliveryOutcome.getDeliveryOutcome()!=null){ + if(!beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).isEmpty()){ + RMNCHBeneficiaryDetailsRmnch rmnchBeneficiaryDetailsRmnch = beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).get(0); + LocalDate marriageDate = rmnchBeneficiaryDetailsRmnch.getDateMarriage() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate deliveryDate = deliveryOutcome.getDateOfDelivery() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + long years = ChronoUnit.YEARS.between(marriageDate, deliveryDate); + + if (years >= 3 && rmnchBeneficiaryDetailsRmnch.getDoYouHavechildren()) { + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.FAMILY_PLANNING.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + } } + + + } - } + + }); + } - }); // JSY_ANC_URBAN // JSY_INST_URBAN @@ -213,7 +308,41 @@ private void createIncentiveRecordforJsy(DeliveryOutcome delOutList, Long benId, try { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getDateOfDelivery(), benId,userRepo.getUserIdByName(delOutList.getUpdatedBy())); + + + if (record == null) { + logger.info("setStartDate" + delOutList.getDateOfDelivery()); + logger.info("setCreatedDate" + delOutList.getCreatedDate()); + record = new IncentiveActivityRecord(); + record.setActivityId(immunizationActivity.getId()); + record.setCreatedDate(delOutList.getDateOfDelivery()); + record.setCreatedBy(delOutList.getCreatedBy()); + record.setStartDate(delOutList.getDateOfDelivery()); + record.setEndDate(delOutList.getDateOfDelivery()); + record.setUpdatedDate(delOutList.getDateOfDelivery()); + record.setUpdatedBy(delOutList.getCreatedBy()); + record.setBenId(benId); + record.setAshaId(userRepo.getUserIdByName(delOutList.getUpdatedBy())); + record.setAmount(Long.valueOf(immunizationActivity.getRate())); + recordRepo.save(record); + } else { + logger.info("benId:" + record.getId()); + + } + } catch (Exception e) { + logger.error("JSY Incentive:", e); + } + + + } + + private void createIncentiveRecordforYearGap(DeliveryOutcome delOutList, Long benId, IncentiveActivity immunizationActivity) { + logger.info("benId" + benId); + + try { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getDateOfDelivery(), benId,userRepo.getUserIdByName(delOutList.getUpdatedBy())); if (record == null) { @@ -225,7 +354,7 @@ record = new IncentiveActivityRecord(); record.setCreatedBy(delOutList.getCreatedBy()); record.setStartDate(delOutList.getDateOfDelivery()); record.setEndDate(delOutList.getDateOfDelivery()); - record.setUpdatedDate(delOutList.getCreatedDate()); + record.setUpdatedDate(delOutList.getDateOfDelivery()); record.setUpdatedBy(delOutList.getCreatedBy()); record.setBenId(benId); record.setAshaId(userRepo.getUserIdByName(delOutList.getUpdatedBy())); diff --git a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java index feb02d9ef..35746b2f8 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java @@ -301,58 +301,18 @@ public String saveLeprosy(LeprosyDTO diseaseControlDTO) { diseaseControlData.setUserId(diseaseControlDTO.getUserId()); } ScreeningLeprosy screeningLeprosy = diseaseLeprosyRepository.save(saveLeprosyData(diseaseControlData)); - if(screeningLeprosy.getIsConfirmed()){ - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForIdentificationLeprosy( - screeningLeprosy.getBenId(), - screeningLeprosy.getTreatmentStartDate(), - screeningLeprosy.getTreatmentEndDate(), - diseaseControlDTO.getUserId()); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); - } - } - if (screeningLeprosy.getIsConfirmed()) { - if(screeningLeprosy.getTypeOfLeprosy()!=null){ - if (screeningLeprosy.getTypeOfLeprosy().equals("PB (Paucibacillary)")) { - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForLeprosyPaucibacillaryConfirmed( - screeningLeprosy.getBenId(), - screeningLeprosy.getTreatmentStartDate(), - screeningLeprosy.getTreatmentEndDate(), - diseaseControlDTO.getUserId()); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); - } - - } - if (screeningLeprosy.getTypeOfLeprosy().equals("MB (Multibacillary)")) { - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForLeprosyMultibacillaryConfirmed( - screeningLeprosy.getBenId(), - screeningLeprosy.getTreatmentStartDate(), - screeningLeprosy.getTreatmentEndDate(), - diseaseControlDTO.getUserId()); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); - } - - } - } - - + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForIdentificationLeprosy( + screeningLeprosy.getBenId(), + screeningLeprosy.getHomeVisitDate(), + screeningLeprosy.getHomeVisitDate(), + diseaseControlDTO.getUserId()); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); } return "Data add successfully"; @@ -391,38 +351,46 @@ private LeprosyFollowUp saveLeprosyFollowUpData(LeprosyFollowUpDTO data) { entity.setModifiedBy(data.getModifiedBy()); entity.setLastModDate( data.getLastModDate() != null ? data.getLastModDate() : new Timestamp(System.currentTimeMillis())); - + if(!leprosyFollowUpRepository.findByBenId(entity.getBenId()).isEmpty()){ + if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=6 && leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()<=12){ + Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForLeprosyPaucibacillaryConfirmed( + entity.getBenId(), + entity.getTreatmentEndDate(), + entity.getTreatmentEndDate(), + userId); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + } + } + + if(!leprosyFollowUpRepository.findByBenId(entity.getBenId()).isEmpty()){ + if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=12){ + Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForLeprosyMultibacillaryConfirmed( + entity.getBenId(), + entity.getTreatmentEndDate(), + entity.getTreatmentEndDate(), + userId); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + } + } return entity; } - private String updateLeprosyFollowUpData(LeprosyFollowUpDTO data, LeprosyFollowUp entity) { - entity.setVisitNumber(data.getVisitNumber()); - entity.setFollowUpDate(data.getFollowUpDate()); - entity.setTreatmentStatus(data.getTreatmentStatus()); - entity.setMdtBlisterPackReceived(data.getMdtBlisterPackReceived()); - entity.setTreatmentCompleteDate(data.getTreatmentCompleteDate()); - entity.setRemarks(data.getRemarks()); - entity.setHomeVisitDate(data.getHomeVisitDate()); - entity.setLeprosySymptoms(data.getLeprosySymptoms()); - entity.setTypeOfLeprosy(data.getTypeOfLeprosy()); - entity.setLeprosySymptomsPosition(data.getLeprosySymptomsPosition()); - entity.setVisitLabel(data.getVisitLabel()); - entity.setLeprosyStatus(data.getLeprosyStatus()); - entity.setReferredTo(data.getReferredTo()); - entity.setReferToName(data.getReferToName()); - entity.setTreatmentEndDate(data.getTreatmentEndDate()); - entity.setMdtBlisterPackRecived(data.getMdtBlisterPackRecived()); - entity.setTreatmentStartDate(data.getTreatmentStartDate()); - - // Update audit info - entity.setModifiedBy(data.getModifiedBy()); - entity.setLastModDate( - data.getLastModDate() != null ? data.getLastModDate() : new Timestamp(System.currentTimeMillis())); - - leprosyFollowUpRepository.save(entity); - return "Follow-up data updated successfully"; - } - @Override public String saveLeprosyFollowUp(LeprosyFollowUpDTO dto) { if (dto == null) @@ -443,68 +411,10 @@ public List getAllLeprosyData(String createdBy) { List dtos = new ArrayList<>(); leprosyList.forEach(leprosy -> { dtos.add(modelMapper.map(leprosy, DiseaseGetLeprosyDTO.class)); - checkAndIncentive(leprosy,leprosy.getUserId()); }); return dtos; } - private void checkAndIncentive(ScreeningLeprosy screeningLeprosy,Integer userId){ - if(screeningLeprosy.getIsConfirmed()){ - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForIdentificationLeprosy( - screeningLeprosy.getBenId(), - screeningLeprosy.getTreatmentStartDate(), - screeningLeprosy.getTreatmentEndDate(), - userId); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); - } - } - if (screeningLeprosy.getIsConfirmed()) { - if(screeningLeprosy.getTypeOfLeprosy()!=null){ - if (screeningLeprosy.getTypeOfLeprosy().equals("PB (Paucibacillary)")) { - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForLeprosyPaucibacillaryConfirmed( - screeningLeprosy.getBenId(), - screeningLeprosy.getTreatmentStartDate(), - screeningLeprosy.getTreatmentEndDate(), - userId); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); - } - - } - if (screeningLeprosy.getTypeOfLeprosy().equals("MB (Multibacillary)")) { - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForLeprosyMultibacillaryConfirmed( - screeningLeprosy.getBenId(), - screeningLeprosy.getTreatmentStartDate(), - screeningLeprosy.getTreatmentEndDate(), - userId); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); - } - - } - } - - - - } - } - @Override public List getAllLeprosyFollowUpData(String createdBy) { logger.info("Fetching leprosy data for createdBy: " + createdBy); @@ -1368,7 +1278,7 @@ private void addIncentive(IncentiveActivity diseaseScreeningActivity, MosquitoNe .findRecordByActivityIdCreatedDateBenId( diseaseScreeningActivity.getId(), visitTimestamp, - diseaseScreening.getBeneficiaryId()); + diseaseScreening.getBeneficiaryId(),diseaseScreening.getUserId()); if (record == null) { @@ -1394,16 +1304,19 @@ record = new IncentiveActivityRecord(); private void addIncentive(IncentiveActivity diseaseScreeningActivity, ScreeningMalaria diseaseScreening) { try { + Timestamp screeningTimestamp = diseaseScreening.getScreeningDate() != null + ? new Timestamp(diseaseScreening.getScreeningDate().getTime()) + : null; IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(diseaseScreeningActivity.getId(), Timestamp.valueOf(diseaseScreening.getCreatedDate().toString()), diseaseScreening.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(diseaseScreeningActivity.getId(), Timestamp.valueOf(diseaseScreening.getCreatedDate().toString()), diseaseScreening.getBenId().longValue(),diseaseScreening.getUserId()); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(diseaseScreeningActivity.getId()); - record.setCreatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); + record.setCreatedDate(screeningTimestamp); record.setCreatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); - record.setStartDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setEndDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); + record.setStartDate(screeningTimestamp); + record.setEndDate(screeningTimestamp); + record.setUpdatedDate(screeningTimestamp); record.setUpdatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); record.setUpdatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); record.setBenId(diseaseScreening.getBenId().longValue()); @@ -1475,8 +1388,9 @@ private void checkIncentive(ChronicDiseaseVisitEntity chronicDiseaseVisitEntity, Integer stateId = userService.getUserDetail(ashaId).getStateId(); IncentiveActivity incentiveActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_FOLLOWUP_TREATMENT", GroupName.NCD.getDisplayName()); IncentiveActivity incentiveActivityCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_FOLLOWUP_TREATMENT", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity incentiveActivityCGForNCDnewPatient = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_NEW_PATIENT_MEDICATION_SUPPORT", GroupName.ACTIVITY.getDisplayName()); logger.info("incentiveActivity:" + incentiveActivity.getId()); - if (incentiveActivity != null) { + if (chronicDiseaseVisitEntity.getFollowUpNo() != null && chronicDiseaseVisitEntity.getCreatedDate() != null && chronicDiseaseVisitEntity.getDiagnosisCodes() != null) { @@ -1487,6 +1401,7 @@ private void checkIncentive(ChronicDiseaseVisitEntity chronicDiseaseVisitEntity, "Cancer" ); + List diagnosisList = Arrays.asList( chronicDiseaseVisitEntity.getDiagnosisCodes().split(",") ); @@ -1494,7 +1409,18 @@ private void checkIncentive(ChronicDiseaseVisitEntity chronicDiseaseVisitEntity, boolean matchFound = diagnosisList.stream() .map(String::trim) .anyMatch(targetDiseases::contains); - + if(matchFound & Integer.valueOf(0).equals(chronicDiseaseVisitEntity.getFollowUpNo()) ){ + LocalDateTime localDateTime = chronicDiseaseVisitEntity.getTreatmentStartDate().atStartOfDay(); + + Timestamp treatmentStartDate = Timestamp.valueOf(localDateTime); + addNCDFolloupIncentiveRecord( + incentiveActivityCGForNCDnewPatient, + ashaId, + chronicDiseaseVisitEntity.getBenId(), + treatmentStartDate, + userName + ); + } if (matchFound && Integer.valueOf(6).equals(chronicDiseaseVisitEntity.getFollowUpNo())) { LocalDateTime localDateTime = chronicDiseaseVisitEntity.getFollowUpDate().atStartOfDay(); @@ -1520,7 +1446,7 @@ private void checkIncentive(ChronicDiseaseVisitEntity chronicDiseaseVisitEntity, } } - } + } @@ -1529,7 +1455,7 @@ private void addNCDFolloupIncentiveRecord(IncentiveActivity incentiveActivity, I Long benId, Timestamp createdDate, String userName) { try { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), createdDate, benId); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), createdDate, benId,ashaId); Timestamp now = Timestamp.valueOf(LocalDateTime.now()); if (record == null) { diff --git a/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java index 76e8dc586..362dc1ea8 100644 --- a/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java @@ -121,7 +121,7 @@ private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, Incent Timestamp ifaVisitDateTimestamp = Timestamp.valueOf(ifaVisitDate.atStartOfDay()); - IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivityAM.getId(),ifaVisitDateTimestamp,ifaFormSubmissionData.getBeneficiaryId()); + IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivityAM.getId(),ifaVisitDateTimestamp,ifaFormSubmissionData.getBeneficiaryId(),userServiceRoleRepo.getUserIdByName(ifaFormSubmissionData.getUserName())); if(incentiveActivityRecord==null){ incentiveActivityRecord = new IncentiveActivityRecord(); incentiveActivityRecord.setActivityId(incentiveActivityAM.getId()); diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java index 2802fa925..b6e4b7c7a 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java @@ -132,7 +132,7 @@ public IncentiveActivityRecord incentiveForLeprosyMultibacillaryConfirmed( return null; } - String activityName = "NLEP_PB_TREATMENT"; + String activityName = "NLEP_MB_TREATMENT"; if (stateCode.equals(StateCode.AM.getStateCode())) { return processIncentive( @@ -159,7 +159,7 @@ public IncentiveActivityRecord incentiveForLeprosyMultibacillaryConfirmed( return null; } catch (Exception e) { - logger.error("Check NLEP_PB_TREATMENT Incentive Exception: ", e); + logger.error("Check NLEP_MB_TREATMENT Incentive Exception: ", e); return null; } } @@ -672,7 +672,7 @@ private IncentiveActivityRecord saveIncentive( // 🔍 duplicate check IncentiveActivityRecord existing = incentiveRecordRepo .findRecordByActivityIdCreatedDateBenId( - activity.getId(), startTimestamp, benId); + activity.getId(), startTimestamp, benId,userId); if (existing != null) { logger.info("Incentive already exists for benId: {}, activityId: {}", diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 5ff7ddb25..f109c88a8 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -22,6 +22,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -33,6 +37,7 @@ import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.Collectors; @@ -78,6 +83,9 @@ public class IncentiveServiceImpl implements IncentiveService { @Autowired private IFAFormSubmissionRepository ifaFormSubmissionRepository; + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + + // ================= MASTER SAVE ================= @Override @@ -187,6 +195,10 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { @Override public String getAllIncentivesByUserId(GetBenRequestHandler request) { + int page = 0; + int size = 20; + Page pageResult; + List finalDtos = new ArrayList<>(); Integer stateCode = userService.getUserDetail(request.getAshaId()).getStateId(); String userName = userService.getUserDetail(request.getAshaId()).getUserName(); @@ -199,7 +211,6 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { checkMonthlyAshaIncentiveForCg(request.getAshaId()); } - checkIncentiveForChildGap(stateCode, userName); } catch (Exception e) { logger.error("Error in checkMonthlyAshaIncentive: ", e); @@ -215,86 +226,105 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { boolean isCG = stateCode != null && stateCode.equals(StateCode.CG.getStateCode()); - // Step 1: Fetch all records for this ASHA - List entities = recordRepo.findRecordsByAsha(request.getAshaId()); + do { - if (entities.isEmpty()) { - return new Gson().toJson(Collections.emptyList()); - } + Pageable pageable = PageRequest.of( + page, + size, + Sort.by("id").descending() // latest first + ); - // Step 2: Collect all activityIds — fetch valid ones in ONE query - List activityIds = entities.stream() - .map(IncentiveActivityRecord::getActivityId) - .distinct() - .collect(Collectors.toList()); + pageResult = recordRepo.findRecordsByAsha( + request.getAshaId(), + pageable + ); - // Single bulk query instead of N individual findIncentiveMasterById() calls - Set validActivityIds = isCG - ? incentivesRepo.findValidActivityIds(activityIds, true) - : incentivesRepo.findValidActivityIds(activityIds, false); + List entities = pageResult.getContent(); - // Filter entities based on valid activity IDs - entities = entities.stream() - .filter(e -> validActivityIds.contains(e.getActivityId())) - .collect(Collectors.toList()); + if (entities.isEmpty()) { + return new Gson().toJson(Collections.emptyList()); + } - // Step 3: Collect all benIds that need name lookup (name == null and benId > 0) - List benIdsToFetch = entities.stream() - .filter(e -> e.getName() == null && e.getBenId() != null && e.getBenId() > 0) - .map(IncentiveActivityRecord::getBenId) - .distinct() - .collect(Collectors.toList()); + // Step 2: Collect all activityIds — fetch valid ones in ONE query + List activityIds = entities.stream() + .map(IncentiveActivityRecord::getActivityId) + .distinct() + .collect(Collectors.toList()); - // Step 4: Bulk fetch all beneficiary names in ONE query instead of 3 queries per record - Map benIdToNameMap = new HashMap<>(); - if (!benIdsToFetch.isEmpty()) { - List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); - for (Object[] row : benDetails) { - Long benId = ((Number) row[0]).longValue(); - String first = row[1] != null ? (String) row[1] : ""; - String last = row[2] != null ? (String) row[2] : ""; - benIdToNameMap.put(benId, (first + " " + last).trim()); - } - } + // Single bulk query instead of N individual findIncentiveMasterById() calls + Set validActivityIds = isCG + ? incentivesRepo.findValidActivityIds(activityIds, true) + : incentivesRepo.findValidActivityIds(activityIds, false); - // Step 5: Map entities to DTOs - List dtos = entities.stream().map(entry -> { - if (entry.getName() == null) { - if (entry.getBenId() != null && entry.getBenId() > 0) { - String name = benIdToNameMap.getOrDefault(entry.getBenId(), ""); - entry.setName(name); - if (isCG) { - entry.setIsEligible(true); - } - } else { - entry.setName(""); - } - if (entry.getVerifiedByUserId() != null) { - entry.setSupervisorRole(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getRoleName()); - entry.setVerifiedByUserName(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getName()); + // Filter entities based on valid activity IDs + entities = entities.stream() + .filter(e -> validActivityIds.contains(e.getActivityId())) + .collect(Collectors.toList()); + // Step 3: Collect all benIds that need name lookup (name == null and benId > 0) + List benIdsToFetch = entities.stream() + .filter(e -> e.getName() == null && e.getBenId() != null && e.getBenId() > 0) + .map(IncentiveActivityRecord::getBenId) + .distinct() + .collect(Collectors.toList()); + + // Step 4: Bulk fetch all beneficiary names in ONE query instead of 3 queries per record + Map benIdToNameMap = new HashMap<>(); + if (!benIdsToFetch.isEmpty()) { + List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); + for (Object[] row : benDetails) { + Long benId = ((Number) row[0]).longValue(); + String first = row[1] != null ? (String) row[1] : ""; + String last = row[2] != null ? (String) row[2] : ""; + benIdToNameMap.put(benId, (first + " " + last).trim()); } - if (entry.getAshaId() != null) { - if (entry.getCreatedBy() == null) { - entry.setCreatedBy(userName); + } + + // Step 5: Map entities to DTOs + List dtos = entities.stream().map(entry -> { + if (entry.getName() == null) { + if (entry.getBenId() != null && entry.getBenId() > 0) { + String name = benIdToNameMap.getOrDefault(entry.getBenId(), ""); + entry.setName(name); + if (isCG) { + entry.setIsEligible(true); + } + } else { + entry.setName(""); } + if (entry.getVerifiedByUserId() != null) { + entry.setSupervisorRole(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getRoleName()); + entry.setVerifiedByUserName(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getName()); - if (entry.getUpdatedBy() == null) { - entry.setUpdatedBy(userName); } + if (entry.getAshaId() != null) { + if (entry.getCreatedBy() == null) { + entry.setCreatedBy(userName); + } + + if (entry.getUpdatedBy() == null) { + entry.setUpdatedBy(userName); + } - if (entry.getIsEligible() == null) { - entry.setIsEligible(true); + if (entry.getIsEligible() == null) { + entry.setIsEligible(true); + } } + + } + return modelMapper.map(entry, IncentiveRecordDTO.class); + }).collect(Collectors.toList()); + finalDtos.addAll(dtos); + + page++; + + } while (pageResult.hasNext()); - } - return modelMapper.map(entry, IncentiveRecordDTO.class); - }).collect(Collectors.toList()); Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); - return gson.toJson(dtos); + return gson.toJson(finalDtos); } // ================= GROUPED SUMMARY ================= @@ -569,27 +599,13 @@ private void incentiveOfNcdReferal(Integer ashaId, Integer stateId) { if (ncdPopEnumeration != null && !cbacDetailsImer.isEmpty()) { - List cbacBenIds = cbacDetailsImer.stream() - .filter(c -> c != null && c.getBeneficiaryRegId() != null) - .map(CbacDetailsImer::getBeneficiaryRegId) - .collect(Collectors.toList()); - - // Batch fetch existing records — 1 query instead of N - Set existingKeys = recordRepo - .findExistingRecords(ncdPopEnumeration.getId(), cbacBenIds, ashaId) - .stream() - .map(r -> r.getActivityId() + "_" + r.getBenId() + "_" + r.getCreatedDate()) - .collect(Collectors.toSet()); final IncentiveActivity activity = ncdPopEnumeration; - cbacDetailsImer.stream() - .filter(c -> c != null && c.getBeneficiaryRegId() != null) - .forEach(c -> { - String key = activity.getId() + "_" + c.getBeneficiaryRegId() + "_" + c.getCreatedDate(); - if (!existingKeys.contains(key)) { - recordsToSave.add(addNCDandCBACIncentiveRecord(activity, ashaId, c.getBeneficiaryRegId(), c.getCreatedDate(), userName)); - } - }); + cbacDetailsImer.forEach(cbacDetailsImer1 -> { + if(cbacDetailsImer1!=null){ + addNCDandCBACIncentiveRecord(activity, ashaId, cbacDetailsImer1.getBeneficiaryRegId(), cbacDetailsImer1.getCreatedDate(), userName); + } + }); } if (hwcReferralEnumeration != null) { @@ -627,21 +643,34 @@ private void incentiveOfNcdReferal(Integer ashaId, Integer stateId) { } // Helper — record banana - private IncentiveActivityRecord addNCDandCBACIncentiveRecord(IncentiveActivity activity, Integer ashaId, + private void addNCDandCBACIncentiveRecord(IncentiveActivity activity, Integer ashaId, Long benId, Timestamp createdDate, String userName) { - Timestamp now = Timestamp.valueOf(LocalDateTime.now()); - IncentiveActivityRecord record = new IncentiveActivityRecord(); - record.setActivityId(activity.getId()); - record.setCreatedDate(createdDate); - record.setCreatedBy(userName); - record.setStartDate(createdDate); - record.setEndDate(createdDate); - record.setUpdatedDate(now); - record.setUpdatedBy(userName); - record.setBenId(benId); - record.setAshaId(ashaId); - record.setAmount(Long.valueOf(activity.getRate())); - return record; + + String lockKey = activity.getId() + "_" + benId + "_" + createdDate; + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + synchronized (lock){ + IncentiveActivityRecord incentiveActivityRecord = recordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId,ashaId); + if(incentiveActivityRecord==null){ + Timestamp now = Timestamp.valueOf(LocalDateTime.now()); + IncentiveActivityRecord record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(createdDate); + record.setCreatedBy(userName); + record.setStartDate(createdDate); + record.setEndDate(createdDate); + record.setUpdatedDate(now); + record.setUpdatedBy(userName); + record.setBenId(benId); + record.setAshaId(ashaId); + record.setAmount(Long.valueOf(activity.getRate())); + recordRepo.save(record); + } + lockMap.remove(lockKey, lock); + + } + + } private String resolveGroupName(Integer stateId) { @@ -654,6 +683,7 @@ private String resolveGroupName(Integer stateId) { } private void checkMonthlyAshaIncentive(Integer ashaId) { + try { String userName = userRepo.getUserNamedByUserId(ashaId); @@ -714,10 +744,10 @@ private void addMonthlyAshaIncentiveRecord(IncentiveActivity incentiveActivity, IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( incentiveActivity.getId(), - startOfMonth, - endOfMonth, 0L, - ashaId + ashaId, + startOfMonth, + endOfMonth ); @@ -753,10 +783,10 @@ private void addHwcReferalAshaIncentiveRecord(IncentiveActivity incentiveActivit IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( incentiveActivity.getId(), - startOfMonth, - endOfMonth, 0L, - ashaId + ashaId, + startOfMonth, + endOfMonth ); @@ -830,166 +860,46 @@ private void addIncentiveForIronTablets(Integer userId) { } private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, IncentiveActivity incentiveActivityAM, Integer userId, String userName) { - Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); - Timestamp startOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(1).atStartOfDay()); Timestamp endOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).atTime(23, 59, 59)); - logger.info("IFA incentive"); - IncentiveActivityRecord incentiveActivityRecord = recordRepo.findRecordByActivityIdCreatedDateBenId( - incentiveActivityAM.getId(), - startOfMonth, - endOfMonth, - 0L, - userId - ); - if (incentiveActivityRecord == null) { - incentiveActivityRecord = new IncentiveActivityRecord(); - incentiveActivityRecord.setActivityId(incentiveActivityAM.getId()); - incentiveActivityRecord.setCreatedDate(timestamp); - incentiveActivityRecord.setStartDate(timestamp); - incentiveActivityRecord.setEndDate(timestamp); - incentiveActivityRecord.setUpdatedDate(timestamp); - incentiveActivityRecord.setUpdatedBy(ifaFormSubmissionData.getUserName()); - incentiveActivityRecord.setCreatedBy(ifaFormSubmissionData.getUserName()); - incentiveActivityRecord.setBenId(0L); - incentiveActivityRecord.setAshaId(userId); - incentiveActivityRecord.setAmount(Long.valueOf(incentiveActivityAM.getRate())); - recordRepo.save(incentiveActivityRecord); - logger.info("saved IFA incentive"); - - } - } - - private void checkIncentiveForChildGap(Integer stateId, String userName) { - - logger.info("Checking Child Gap Incentive for user: {}, stateId: {}", userName, stateId); - - List eligibleCoupleRegisters = eligibleCoupleRegisterRepo.findByCreatedBy(userName); - - logger.info("Eligible Couple Records Found: {}", eligibleCoupleRegisters.size()); - - if (!eligibleCoupleRegisters.isEmpty()) { - - eligibleCoupleRegisters.forEach(eligibleCoupleRegister -> { - - logger.info( - "Processing EligibleCoupleRegister -> BenId: {}, NumChildren: {}, MarriageFirstChildGap: {}, FirstAndSecondChildGap: {}", - eligibleCoupleRegister.getBenId(), - eligibleCoupleRegister.getNumChildren(), - eligibleCoupleRegister.getMarriageFirstChildGap(), - eligibleCoupleRegister.getFirstAndSecondChildGap()); - - // Marriage -> First Child Gap - if(eligibleCoupleRegister.getFirstAndSecondChildGap()!=null){ - if (eligibleCoupleRegister.getFirstAndSecondChildGap()>=3 ) { - - logger.info("Marriage -> First Child Gap condition matched."); - - if (stateId.equals(StateCode.AM.getStateCode())) { - - logger.info("Fetching incentive for Assam."); - - IncentiveActivity activity1 = - incentivesRepo.findIncentiveMasterByNameAndGroup( - "FP_DELAY_2Y", - GroupName.FAMILY_PLANNING.getDisplayName()); - - logger.info("Incentive Activity: {}", activity1); - - createIncentiveRecord(eligibleCoupleRegister, activity1); - - logger.info("Marriage -> First Child Gap incentive created."); - } - - if (stateId.equals(StateCode.CG.getStateCode())) { - - logger.info("Fetching incentive for Chhattisgarh."); - - IncentiveActivity activityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup( - "FP_DELAY_2Y", - GroupName.ACTIVITY.getDisplayName()); - - logger.info("Incentive Activity: {}", activityCH); - - createIncentiveRecord(eligibleCoupleRegister, activityCH); - - logger.info("Marriage -> First Child Gap incentive created."); - } - } - } - + String lockKey = incentiveActivityAM.getId() + "_" + 0 + "_" + startOfMonth; - // First -> Second Child Gap - if(eligibleCoupleRegister.getMarriageFirstChildGap()!=null){ - if (eligibleCoupleRegister.getMarriageFirstChildGap()>=2) { - - logger.info("1st -> 2nd Child Gap condition matched."); - - if (stateId.equals(StateCode.AM.getStateCode())) { - - logger.info("Fetching incentive for Assam."); - - IncentiveActivity activity2 = - incentivesRepo.findIncentiveMasterByNameAndGroup( - "1st_2nd_CHILD_GAP", - GroupName.FAMILY_PLANNING.getDisplayName()); - - logger.info("Incentive Activity: {}", activity2); - - createIncentiveRecord(eligibleCoupleRegister, activity2); - - logger.info("1st -> 2nd Child Gap incentive created."); - } - - if (stateId.equals(StateCode.CG.getStateCode())) { - - logger.info("Fetching incentive for Chhattisgarh."); - - IncentiveActivity activityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup( - "1st_2nd_CHILD_GAP", - GroupName.ACTIVITY.getDisplayName()); - - logger.info("Incentive Activity: {}", activityCH); + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); - createIncentiveRecord(eligibleCoupleRegister, activityCH); - logger.info("1st -> 2nd Child Gap incentive created."); - } - } - } + logger.info("IFA incentive"); + synchronized (lock){ + IncentiveActivityRecord incentiveActivityRecord = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivityAM.getId(), + 0L, + userId, + startOfMonth, + endOfMonth + ); + if (incentiveActivityRecord == null) { + incentiveActivityRecord = new IncentiveActivityRecord(); + incentiveActivityRecord.setActivityId(incentiveActivityAM.getId()); + incentiveActivityRecord.setCreatedDate(timestamp); + incentiveActivityRecord.setStartDate(timestamp); + incentiveActivityRecord.setEndDate(timestamp); + incentiveActivityRecord.setUpdatedDate(timestamp); + incentiveActivityRecord.setUpdatedBy(ifaFormSubmissionData.getUserName()); + incentiveActivityRecord.setCreatedBy(ifaFormSubmissionData.getUserName()); + incentiveActivityRecord.setBenId(0L); + incentiveActivityRecord.setAshaId(userId); + incentiveActivityRecord.setAmount(Long.valueOf(incentiveActivityAM.getRate())); + recordRepo.save(incentiveActivityRecord); + logger.info("saved IFA incentive"); - }); + } - } else { - logger.info("No Eligible Couple Register records found for user: {}", userName); } + lockMap.remove(lockKey, lock); - logger.info("Completed Child Gap Incentive check for user: {}", userName); - } - private void createIncentiveRecord(EligibleCoupleRegister eligibleCoupleRegister, IncentiveActivity activity) { - if (activity != null) { - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(activity.getId(), eligibleCoupleRegister.getCreatedDate(), eligibleCoupleRegister.getBenId()); - Integer userId = userRepo.getUserIdByName(eligibleCoupleRegister.getCreatedBy()); - if (record == null) { - record = new IncentiveActivityRecord(); - record.setActivityId(activity.getId()); - record.setCreatedDate(eligibleCoupleRegister.getCreatedDate()); - record.setCreatedBy(eligibleCoupleRegister.getCreatedBy()); - record.setStartDate(eligibleCoupleRegister.getCreatedDate()); - record.setEndDate(eligibleCoupleRegister.getCreatedDate()); - record.setUpdatedDate(eligibleCoupleRegister.getCreatedDate()); - record.setUpdatedBy(eligibleCoupleRegister.getCreatedBy()); - record.setBenId(eligibleCoupleRegister.getBenId()); - record.setAshaId(userId); - record.setAmount(Long.valueOf(activity.getRate())); - recordRepo.save(record); - } - } } + } diff --git a/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java index 03af282a7..bd0409903 100644 --- a/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java @@ -98,7 +98,7 @@ private void checkAndGenerateIncentive(List infantList) { } private void addIsSncuIncentive(IncentiveActivity activity, Long benId, String createdBy, Timestamp createdDate) { - IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId); + IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId,userServiceRoleRepo.getUserIdByName(createdBy)); if(incentiveActivityRecord==null){ incentiveActivityRecord = new IncentiveActivityRecord(); diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 0b14f90ab..41849ee3c 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -29,6 +29,7 @@ import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Service @@ -91,6 +92,9 @@ public class MaternalHealthServiceImpl implements MaternalHealthService { public static final List PNC_PERIODS = Arrays.asList("1st Day", "3rd Day", "7th Day", "14th Day", "21st Day", "28th Day", "42nd Day"); + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + + @Override public String registerPregnantWoman(List pregnantWomanDTOs) { @@ -148,7 +152,7 @@ public List getANCVisits(GetBenRequestHandler dto) { .map(anc -> mapper.convertValue(anc, ANCVisitDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { - logger.error("ANC VISIT :---------------------"+e.getMessage()); + logger.error("ANC VISIT :---------------------" + e.getMessage()); } return null; } @@ -170,7 +174,7 @@ public String saveANCVisit(List ancVisitDTOs, Integer userId) { List ancVisitList = ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(it.getBenId(), it.getAncVisit(), true); ANCVisit ancVisit = new ANCVisit(); - if(!ancVisitList.isEmpty()){ + if (!ancVisitList.isEmpty()) { ancVisit = ancVisitList.get(0); } logger.info("ANC visit fetch completed"); @@ -351,7 +355,7 @@ private void checkAndAddHighRisk(List pmsmaList) { private void addIncentiveForHighRisk(IncentiveActivity incentiveActivity, PMSMA pmsma) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), pmsma.getCreatedDate(), pmsma.getBenId()); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), pmsma.getCreatedDate(), pmsma.getBenId(),userRepo.getUserIdByName(pmsma.getCreatedBy())); // get bene details if (record == null) { @@ -375,11 +379,6 @@ public List getPNCVisits(GetBenRequestHandler dto) { try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); List pncVisits = pncVisitRepo.getPNCForPW(user); - pncVisits.forEach(pncVisit -> { - checkAndAddAntaraIncentive(pncVisit); - - }); - return pncVisits.stream() .map(pnc -> mapper.convertValue(pnc, PNCVisitDTO.class)) .collect(Collectors.toList()); @@ -448,7 +447,7 @@ public String savePNCVisit(List pncVisitDTOs) { @Override @Transactional public String saveANCVisitQuestions(List dtos, String authorization) throws IEMRException { - Integer userId = jwtUtil.extractUserId(authorization); + Integer userId = jwtUtil.extractUserId(authorization); String userName = userRepo.getUserNamedByUserId(userId); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); @@ -595,7 +594,7 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { logger.info("ContraceptionMethod:" + ect.getContraceptionMethod()); // logic for assam - if(stateId.equals(StateCode.AM.getStateCode())){ + if (stateId.equals(StateCode.AM.getStateCode())) { if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("MALE STERILIZATION")) { IncentiveActivity maleSterilizationActivityAM = @@ -646,33 +645,49 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { } // logic for cg - if(stateId.equals(StateCode.CG.getStateCode())){ + if (stateId.equals(StateCode.CG.getStateCode())) { + if (ect.getAnyContraceptionMethod() != null) { + if (ect.getAnyContraceptionMethod()) { + IncentiveActivity femaleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity PPIUCDActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity PPIUCDActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.ACTIVITY.getDisplayName()); - if (PPIUCDActivityCH != null) { - addIncenticeRecord(ect, userId, PPIUCDActivityCH); - } + IncentiveActivity maleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity femaleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); + if (PPIUCDActivityCH != null) { + if (ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD)")) { + addIncenticeRecord(ect, userId, PPIUCDActivityCH); + + } + } + + + if (femaleSterilizationActivityCH != null) { + if (ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityCH); + + } + } - if (femaleSterilizationActivityCH != null) { - addIncenticeRecord(ect, userId, femaleSterilizationActivityCH); - } - IncentiveActivity maleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); + if (maleSterilizationActivityCH != null) { + if (ect.getContraceptionMethod().equals("MALE STERILIZATION")) { + addIncenticeRecord(ect, userId, maleSterilizationActivityCH); + + } + } + } - if (maleSterilizationActivityCH != null) { - addIncenticeRecord(ect, userId, maleSterilizationActivityCH); } - if(ect.getMotherDangerSign() != null + + if (ect.getMotherDangerSign() != null && !ect.getMotherDangerSign().isEmpty() - && ect.getPncPeriod() == 42){ + && ect.getPncPeriod() == 42) { IncentiveActivity highRiskPostpartumCareActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); if (highRiskPostpartumCareActivityCH != null) { @@ -682,8 +697,6 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { } if (ect.getPncPeriod() == 42) { - - IncentiveActivity highRiskPostpartumHealthCareActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); @@ -714,25 +727,35 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { } + + @Transactional private void addIncenticeRecord(PNCVisit ect, Integer userId, IncentiveActivity antaraActivity) { - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getCreatedDate(), ect.getBenId()); - // get bene details - if (record == null) { - record = new IncentiveActivityRecord(); - record.setActivityId(antaraActivity.getId()); - record.setCreatedDate(ect.getPncDate()); - record.setCreatedBy(ect.getCreatedBy()); - record.setStartDate(ect.getPncDate()); - record.setEndDate(ect.getPncDate()); - record.setUpdatedDate(ect.getPncDate()); - record.setUpdatedBy(ect.getCreatedBy()); - record.setBenId(ect.getBenId()); - record.setAshaId(userId); - record.setAmount(Long.valueOf(antaraActivity.getRate())); - recordRepo.save(record); + String lockKey = antaraActivity.getId() + "_" + ect.getBenId() + "_" + ect.getPncDate(); + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + + synchronized (lock) { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getPncDate(), ect.getBenId(),userId); + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(antaraActivity.getId()); + record.setCreatedDate(ect.getPncDate()); + record.setCreatedBy(ect.getCreatedBy()); + record.setStartDate(ect.getPncDate()); + record.setEndDate(ect.getPncDate()); + record.setUpdatedDate(ect.getPncDate()); + record.setUpdatedBy(ect.getCreatedBy()); + record.setBenId(ect.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(antaraActivity.getRate())); + recordRepo.save(record); + } } + + lockMap.remove(lockKey, lock); } @@ -748,16 +771,23 @@ private void checkAndAddIncentives(List ancList, Integer userId) { IncentiveActivity ancFullActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( "FULL_ANC", GroupName.MATERNAL_HEALTH.getDisplayName()); IncentiveActivity identifiedHrpActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("EPMSMA_HRP_IDENTIFIED", GroupName.MATERNAL_HEALTH.getDisplayName()); - IncentiveActivity comprehensiveAbortionActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + IncentiveActivity comprehensiveAbortionActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( "COMPREHENSIVE_ABORTION_CARE", GroupName.MATERNAL_HEALTH.getDisplayName()); IncentiveActivity paiucdActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( "FP_PAIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + IncentiveActivity iucdActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_IUCD", GroupName.FAMILY_PLANNING.getDisplayName()); ancList.forEach(ancVisit -> { - - if (paiucdActivityAM != null && ancVisit.getIsPaiucdId() != null - && ancVisit.getIsPaiucdId().toString().equals("1")) { - recordAncRelatedIncentive(paiucdActivityAM, ancVisit); + if(ancVisit.getIsAborted()){ + if (paiucdActivityAM != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==2 && + ancVisit.getIsPaiucd().toString().contains("Tubectomy")) { + recordAncRelatedIncentive(paiucdActivityAM, ancVisit); + } + if (iucdActivityAM != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==1 && + ancVisit.getIsPaiucd().toString().contains("Copper-T")) { + recordAncRelatedIncentive(iucdActivityAM, ancVisit); + } } @@ -791,7 +821,7 @@ private void checkAndAddIncentives(List ancList, Integer userId) { // ✅ State 8 if (stateId.equals(8)) { - IncentiveActivity ancFullActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + IncentiveActivity ancFullActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( "ANC_FOUR_CHECKUPS_SUPPORT", GroupName.ACTIVITY.getDisplayName()); IncentiveActivity comprehensiveAbortionActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( "COMPREHENSIVE_ABORTION_CARE", GroupName.ACTIVITY.getDisplayName()); @@ -800,15 +830,24 @@ private void checkAndAddIncentives(List ancList, Integer userId) { IncentiveActivity paiucdActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( "FP_PAIUCD", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity iucdActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_IUCD", GroupName.ACTIVITY.getDisplayName()); + ancList.forEach(ancVisit -> { - if ( ancVisit.getIsAborted()) { - recordAncRelatedIncentive(paiucdActivityCH, ancVisit); + if (ancVisit.getIsAborted()) { + if (paiucdActivityCH != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==2 && + ancVisit.getIsPaiucd().toString().contains("Tubectomy")) { + recordAncRelatedIncentive(paiucdActivityCH, ancVisit); + } + if (iucdActivityCH != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==1 + && ancVisit.getIsPaiucd().toString().contains("Copper-T")) { + recordAncRelatedIncentive(iucdActivityCH, ancVisit); + } } - if (ancFullActivityCH != null && ancVisit.getAncVisit() != null && ancVisit.getAncVisit() == 4) { recordAncRelatedIncentive(ancFullActivityCH, ancVisit); @@ -823,13 +862,13 @@ private void checkAndAddIncentives(List ancList, Integer userId) { } - } private void recordAncRelatedIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { - IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), ancVisit.getCreatedDate(), ancVisit.getBenId()); Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), ancVisit.getCreatedDate(), ancVisit.getBenId(),userId); + if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(incentiveActivity.getId()); @@ -848,6 +887,7 @@ record = new IncentiveActivityRecord(); } private void recordAncFirstTRIMIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { + Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); if (ancVisit.getAncDate() == null || ancVisit.getLmpDate() == null) { return; @@ -865,10 +905,9 @@ private void recordAncFirstTRIMIncentive(IncentiveActivity incentiveActivity, AN IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( incentiveActivity.getId(), ancVisit.getCreatedDate(), - ancVisit.getBenId() + ancVisit.getBenId(),userId ); - Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); if (record == null) { record = new IncentiveActivityRecord(); @@ -887,11 +926,14 @@ record = new IncentiveActivityRecord(); } private void recordFullAncIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { - + Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); + if (userId == null) { + return; + } IncentiveActivityRecord existRecord = recordRepo.findRecordByActivityIdCreatedDateBenId( incentiveActivity.getId(), - ancVisit.getCreatedDate(), - ancVisit.getBenId() + ancVisit.getAncDate(), + ancVisit.getBenId(),userId ); @@ -899,11 +941,6 @@ private void recordFullAncIncentive(IncentiveActivity incentiveActivity, ANCVisi return; } - Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); - if (userId == null) { - return; - } - IncentiveActivityRecord record = new IncentiveActivityRecord(); record.setActivityId(incentiveActivity.getId()); record.setCreatedDate(ancVisit.getAncDate()); 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 92493c751..e89928def 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -66,15 +66,11 @@ public String save(List request, String authorisation) throw entity.setReasonForNotCompleting(dto.getReasonForNotCompleting()); if(entity!=null){ repository.save(entity); - checkIncentive(entity); } } - - - response.setResponse("TB Confirmed case saved successfully"); } else { @@ -96,21 +92,21 @@ private void checkIncentive(TBConfirmedCase entity){ || "Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen); if (Boolean.TRUE.equals(entity.getTreatmentCompleted()) - && entity.getActualTreatmentCompletionDate() != null) { + && entity.getExpectedTreatmentCompletionDate() != null) { if (isDrTb) { incentiveLogicService.incentiveForTbFollowUpIsDrTb( entity.getBenId(), - Timestamp.valueOf(entity.getTreatmentStartDate().atStartOfDay()), - Timestamp.valueOf(entity.getActualTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), entity.getUserId() ); } else { incentiveLogicService.incentiveForTbFollowUp( entity.getBenId(), - Timestamp.valueOf(entity.getTreatmentStartDate().atStartOfDay()), - Timestamp.valueOf(entity.getActualTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), entity.getUserId() ); diff --git a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java index 4519bc623..7f1104d1d 100644 --- a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java @@ -24,7 +24,6 @@ */ package com.iemr.flw.service.impl; -import com.iemr.flw.controller.CoupleController; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; @@ -150,12 +149,8 @@ private Boolean saveVhncFormData(VhncFormDTO vhncFormDTO, Integer userID) { vhncForm.setFormType("VHNC"); vhncFormRepo.save(vhncForm); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); - - LocalDate localDate = LocalDate.parse(vhncForm.getVhncDate(), formatter); - Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - incentiveLogicService.incentiveForAttendingVhsnc(0L,date,date,Math.toIntExact(vhncForm.getUserId())); + checkVhncIncentive(vhncForm.getCreatedDate(),Math.toIntExact(vhncForm.getUserId())); return true; } @@ -175,12 +170,8 @@ private Boolean savePhcForm(PhcReviewMeetingFormDTO dto, Integer userID) { phcReviewForm.setImage2(dto.getImage2()); phcReviewForm.setFormType("PHC"); phcReviewFormRepo.save(phcReviewForm); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); - LocalDate localDate = LocalDate.parse(phcReviewForm.getPhcReviewDate(), formatter); - - Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - incentiveLogicService.incentiveForClusterMeeting(0L,date,date,Math.toIntExact(phcReviewForm.getUserId())); + checkPhcMeetingIncentive(phcReviewForm.getCreatedDate(),Math.toIntExact(phcReviewForm.getUserId())); return true; } @@ -286,18 +277,121 @@ private Boolean saveVhndFormData(VHNDFormDTO vhndFormDTO, Integer userID) { : null); vhndForm.setFormType("VHND"); vhndRepo.save(vhndForm); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); - LocalDate localDate = LocalDate.parse(vhndForm.getVhndDate(), formatter); - Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); - incentiveLogicService.incentiveForVhndMeeting(0L,date,date,vhndForm.getUserId()); + checkVhndIncentive(vhndForm.getCreatedDate(),vhndForm.getUserId()); return true; } + private void checkVhndIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("VHND_PARTICIPATION", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + + private void checkPhcMeetingIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("CLUSTER_MEETING", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + + + private void checkVhncIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("VHSNC_MEETING", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + @Override public List getAll(GetVillageLevelRequestHandler getVillageLevelRequestHandler) { From b7642fc6389101ba98e34e6513b2783f15ab1d6a Mon Sep 17 00:00:00 2001 From: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:15:15 +0530 Subject: [PATCH 011/237] Feature/firebase notification incentive approval (#300) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix duplicate incentive for mdsr * fix duplicate incentive for mdsr * fix duplicate incentive for mdsr * fix duplicate incentive for mdsr * fix supervisor name * Client ID and Client Secret Disclosure (#239) * fix: client id and client secert key handle in backend * fix: client id and client secert key handle in backend * fix: remove hardcoded ABHA credentials and prevent local properties from being committed - Remove common_local.properties from git tracking (had hardcoded SBX_001542 client id/secret) - Add common_local.properties to .gitignore to prevent future commits - Add ABHA token config sample entries to common_example.properties Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 * feat: add facilityData to getUserDetail response based on user role (#240) Add FacilityDataService to build facilityData block (location, facilities, ashaList, totalAshaCount) based on userId and roleName — same logic as login response. ASHA Supervisor gets mapped ashaList, ASHA gets facility + supervisor + peers, CHO/ANM get facilities + ashaList at same facility. Co-authored-by: Claude Sonnet 4.6 * fix(security): replace extractUsername(token) with DB lookup across FLW-API (#241) All usages of jwtUtil.extractUsername (which reads PII from JWT sub claim) replaced with userRepo.getUserNamedByUserId(jwtUtil.extractUserId(token)). Username is now fetched from DB using userId — token PII not used anywhere in FLW-API. Affects BeneficiaryService, MaternalHealth, DiseaseControl, Campaign, IRSRound, SupervisorDashboard. Co-authored-by: Claude Sonnet 4.6 * feat: add mobile and employeeId to peersAtFacility, ashaList and supervisor in facilityData (#242) Co-authored-by: Claude Sonnet 4.6 * incentive chnages for release 3.8.2 * incentive chnages for release 3.8.2 * incentive chnages for release 3.8.2 * incentive chnages for release 3.8.2 * fix incentive issue for production (#243) * fix incentive issue for production * fix incentive issue for production * fix incentive issue for production * fix incentive issue for production * fix incentive issue on cg * fix incentive issue on cg * fix incentive issue on cg * fix incentive issue on cg * fix incentive issue on cg * fix incentive issue on cg * fix incentive * fix incentive * fix incentive * fix incentive * fix incentive * fix incentive issue and api response issue * fix incentive issue and api response issue * add unclaimed incentive count on dashboard * fix incentive issue in 3.8.2 * fix incentive issue in 3.8.2 * fix incentive issue in 3.8.2 * fix TB suspected incentive * Fix incentive for ANC * Fix incentive for ANC * Fix incentive for ANC * Fix incentive for ANC * fix ifa incentive * fix For motivating Female sterilization * fix For motivating Female sterilization * fix incentive for NCD follow up * fix pnc related incentive * fix pnc related incentive * fix IFA incentive logic issue * fix IFA incentive logic issue * fix IFA incentive logic issue * fix IFA incentive logic issue * fix IFA incentive logic issue * fixed malaria followup incentive * fixed malaria followup incentive * fixed malaria followup incentive * get ben details using abha ID * get ben details using abha ID * fix isDeactivate issue * Fix: Handled isDeactivate null values for old data records by defaulting to false. * Fix: Handled isDeactivate null values for old data records by defaulting to false. (#246) * fix motivating couples to maintain at least a two-year gap after marriage before first child * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * Motivating 70% women to take iron tablets * fix hbnc related incentive issue * fix hbnc related incentive issue * fix hbnc related incentive issue * fix hbnc related incentive issue * fix hbnc related incentive issue * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * add get bene deatils using nic api * fix incentive for Is Paiucd * add abha govt username and password * add abha govt username and password * add abha govt username and password * fix query issue in userService role * fix query issue in userService role * fix query issue in userService role * fix query issue in userService role * fix query issue in userService role * Fix/query issue in userservicerole (#249) * Fix: Handled isDeactivate null values for old data records by defaulting to false. * fix query issue in userService role * handel duplicate ben record * Fix/status code in ors ifa (#251) * Fix: Handled isDeactivate null values for old data records by defaulting to false. * change status code * change status code * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * handel duplicate record * fix sync issue * fix sync issue * fix sync issue * feature of abha check in our system * feature of abha check in our system * hbyc issue fixed * hbyc issue fixed * hbyc issue fixed * hbyc issue fixed * hbyc issue fixed * hbyc issue fixed * fix internal server error on abha id * fix internal server error on abha id * fix internal server error on abha id * fix internal server error on abha id * fix internal server error on abha id * fix internal server error on abha id * fix sam get api issue * fix date of referral issue * fix date of referral issue * fix date of referral issue * fix date of referral issue * fix hwc referral incentive issue * fix hwc referral incentive issue * fix hwc referral incentive issue * fix hwc referral incentive issue * fix hwc referral incentive issue * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * Incentive logic for first-year child Immunization * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix child year gap * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix duplicate record in child gap incentive * fix hbnc incentive * fix hbnc incentive * fix hbnc incentive * Fix/asha profile image issue (#265) * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix asha profile image issue * fix pnc incentive * fix pnc incentive * fix pnc incentive * fix vhnd incentive incentive * fix vhnd incentive incentive * fix vhnd incentive error * fix vhnd incentive error * fix vhnd incentive error * fix vhnd incentive error * fix cluster meeting incentive error * fix cluster meeting incentive error * fix tb incentive * fix slide test incentive * Fix/pb mb incentive issue 3.8.2 (#271) * fix duplicate incentive issue * fix duplicate incentive issue * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix child after 2 year gap after marriage * fix hbyc incentive logic * fix hbyc incentive logic * fix hbyc incentive logic * optmiz query for incentive logic for hbnc * optmiz query for incentive logic for hbnc * Implemetation of in app notification * fixed hbnc and leprosy incentive (#290) * fixed hbnc and leprosy incentive (#291) * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * feature of incentive approval and notification * change base url of notification * change base url of notification * change base url of notification * change base url of notification * change base url of notification * change base url of notification * implement get supervisor id by asha * implement get supervisor id by asha * implement get supervisor id by asha * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix supervisor incentive approval status * fix role issue for supervisor * fix role issue for supervisor * fix role issue for supervisor * fix role issue for supervisor * fix role issue for supervisor * fix role issue for supervisor * fix role issue for supervisor * handel approval of incentive for ANM * handel approval of incentive for ANM * handel approval of incentive for ANM * handel approval of incentive for ANM * handel approval of incentive for ANM * handel approval of incentive for ANM * handel approval of incentive for ANM * handel approval of incentive for ANM * fix incentive new logic changes * fix incentive new logic changes * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic --------- Co-authored-by: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 --- src/main/environment/common_ci.properties | 1 + src/main/environment/common_docker.properties | 3 + .../AshaSupervisorIncentiveApproval.java | 2 + .../flw/controller/IncentiveController.java | 5 +- .../controller/NotificationController.java | 160 +++++++ .../flw/domain/iemr/IncentiveActivity.java | 8 + .../iemr/flw/domain/iemr/Notification.java | 67 +++ .../flw/domain/iemr/UserFcmTokenData.java | 23 + .../iemr/flw/dto/iemr/NotificationDTO.java | 13 + .../flw/dto/iemr/NotificationListDTO.java | 24 + .../dto/iemr/SendNotificationRequestDTO.java | 18 + .../flw/repo/iemr/IncentiveRecordRepo.java | 97 +++- .../flw/repo/iemr/NotificationRepository.java | 35 ++ .../repo/iemr/SupervisorDashboardRepo.java | 63 ++- .../iemr/flw/repo/iemr/UserFcmTokenRepo.java | 34 ++ .../iemr/flw/service/IncentiveService.java | 2 +- .../iemr/flw/service/NotificationService.java | 14 + .../service/impl/ChildCareServiceImpl.java | 61 +-- .../impl/DeliveryOutcomeServiceImpl.java | 2 +- .../impl/DiseaseControlServiceImpl.java | 26 +- .../service/impl/IncentiveServiceImpl.java | 101 +++- .../impl/NotificationSchedulerService.java | 9 - .../flw/service/impl/NotificationService.java | 81 ---- .../service/impl/NotificationServiceImpl.java | 222 +++++++++ .../impl/SupervisorDashboardServiceImpl.java | 437 +++++++++++++++--- .../impl/VillageLevelFormServiceImpl.java | 2 + src/main/resources/application.properties | 2 +- 27 files changed, 1260 insertions(+), 252 deletions(-) create mode 100644 src/main/java/com/iemr/flw/controller/NotificationController.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/Notification.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/UserFcmTokenData.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/NotificationDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/NotificationListDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/SendNotificationRequestDTO.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/NotificationRepository.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/UserFcmTokenRepo.java create mode 100644 src/main/java/com/iemr/flw/service/NotificationService.java delete mode 100644 src/main/java/com/iemr/flw/service/impl/NotificationService.java create mode 100644 src/main/java/com/iemr/flw/service/impl/NotificationServiceImpl.java diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 238d5f926..50ae20303 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -1,6 +1,7 @@ fhir-url = @env.FHIR_API@ tm-url = @env.TM_API@ +common-api-base-url=@env.COMMON_API@ ##--------------------------------------------## Primary db------------------------------------------------------------------- diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index 073091334..8a31d5d6f 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -1,5 +1,8 @@ fhir-url = ${FHIR_API} tm-url = ${TM_API} +common-api-base-url=${COMMON_API} + + ##--------------------------------------------## Primary db------------------------------------------------------------------- diff --git a/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java index 3f840f614..3ba457a64 100644 --- a/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java +++ b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java @@ -37,6 +37,7 @@ public ResponseEntity getAshaListByFacility( @RequestHeader(value = "JwtToken") String token) { try { + logger.info("getAshaListByFacility request{}",request.getFacilityId()); if (token == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("UNAUTHORIZED"); @@ -71,6 +72,7 @@ public ResponseEntity getAshaListByFacility( @PostMapping("/dashboard") public String getSupervisorDashboard(@RequestBody AshaByFacilityRequestDTO request,@RequestHeader(value = "JwtToken") String token ) { OutputResponse response = new OutputResponse(); + logger.info("dashboard request{}",request.getFacilityId()); try { if(token!=null){ diff --git a/src/main/java/com/iemr/flw/controller/IncentiveController.java b/src/main/java/com/iemr/flw/controller/IncentiveController.java index fe1d93ac2..5feead211 100644 --- a/src/main/java/com/iemr/flw/controller/IncentiveController.java +++ b/src/main/java/com/iemr/flw/controller/IncentiveController.java @@ -112,14 +112,15 @@ public String getAllIncentivesByUserId(@RequestBody GetBenRequestHandler request @Operation(summary = "get high risk assessment data of all beneficiaries registered with given user id") @RequestMapping(value = {"/claimedIncentiveByUser"}, method = {RequestMethod.POST}) public String getAllIncentivesByUserIdGroupByCount(@RequestBody GetBenRequestHandler requestDTO, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "jwtToken") String jwtToken) { OutputResponse response = new OutputResponse(); try { if (requestDTO != null) { + Integer userId= jwtUtil.extractUserId(jwtToken); logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + requestDTO); - String s = incentiveService.getAllIncentivesGroupedSummary(requestDTO); + String s = incentiveService.getAllIncentivesGroupedSummary(requestDTO,userId); logger.info("User Incentive:" + s); if (s != null) response.setResponse(s); diff --git a/src/main/java/com/iemr/flw/controller/NotificationController.java b/src/main/java/com/iemr/flw/controller/NotificationController.java new file mode 100644 index 000000000..54d0443e4 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/NotificationController.java @@ -0,0 +1,160 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.iemr.NotificationListDTO; +import com.iemr.flw.dto.iemr.SendNotificationRequestDTO; +import com.iemr.flw.service.NotificationService; +import com.iemr.flw.utils.JwtUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/notification") +public class NotificationController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private NotificationService notificationService; + + /** GET /notifications/{receiverUserId}?page=0&size=20 */ + @PostMapping("/list") + public Map listNotifications(@RequestHeader(value = "JwtToken") String token) { + Map response = new HashMap<>(); + try { + Integer receiverUserId = jwtUtil.extractUserId(token); + if (receiverUserId != null) { + NotificationListDTO notificationListDTO = + notificationService.getNotifications(receiverUserId); + + if (notificationListDTO != null) { + response.put("statusCode", 200); + response.put("data", notificationListDTO); + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in get data : " + e); + response.put("statusCode", 5000); + response.put("error", "Error in get data : " + e); + } + return response; + } + + /** GET /notifications/{receiverUserId}/unread-count */ + @GetMapping("/{receiverUserId}/unread-count") + public Map unreadCount(@PathVariable Integer receiverUserId) { + Map response = new HashMap<>(); + try { + + if (receiverUserId != null) { + Long unreadCount = notificationService.getUnreadCount(receiverUserId); + + if (unreadCount != null) { + response.put("statusCode", 200); + response.put("data", unreadCount); + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in get data : " + e); + response.put("statusCode", 5000); + response.put("error", "Error in get data : " + e); + } + return response; + } + + /** PUT /notifications/{notificationId}/read */ + @PutMapping("/{notificationId}/read") + public Map markAsRead(@PathVariable Long notificationId) { + Map response = new HashMap<>(); + try { + if (notificationId != null) { + boolean success = notificationService.markAsRead(notificationId); + + response.put("statusCode", 200); + response.put("data", success); + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in update data : " + e); + response.put("statusCode", 5000); + response.put("error", "Error in update data : " + e); + } + return response; + } + + /** POST /notifications/send */ + @PostMapping("/send") + public Map sendNotification(@RequestBody SendNotificationRequestDTO request) { + Map response = new HashMap<>(); + try { + if (request != null) { + String result = notificationService.sendNotification( + request.getAppType(), + request.getTopic(), + request.getTitle(), + request.getBody(), + request.getRedirect(), + request.getNotificationType(), + request.getReceiverId()); + + if (result != null) { + response.put("statusCode", 200); + response.put("data", result); + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in send notification : " + e); + response.put("statusCode", 5000); + response.put("error", "Error in send notification : " + e); + } + return response; + } + + /** PUT /notifications/{receiverUserId}/read-all */ + @PutMapping("/{receiverUserId}/read-all") + public Map markAllAsRead(@PathVariable Integer receiverUserId) { + Map response = new HashMap<>(); + try { + if (receiverUserId != null) { + int updatedCount = notificationService.markAllAsRead(receiverUserId); + + response.put("statusCode", 200); + response.put("data", updatedCount); + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in update data : " + e); + response.put("statusCode", 5000); + response.put("error", "Error in update data : " + e); + } + return response; + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index 016f6271d..a37f15017 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -57,6 +57,14 @@ public class IncentiveActivity { @Column(name = "is_deleted") private Boolean isDeleted; + @Column(name = "state_activity_code") + private Integer stateActivityCode; + + @Column(name = "is_default_activity") + private Boolean isDefaultActivity; + + + @Column(name = "state_activity_code") private Integer stateActivityCode; diff --git a/src/main/java/com/iemr/flw/domain/iemr/Notification.java b/src/main/java/com/iemr/flw/domain/iemr/Notification.java new file mode 100644 index 000000000..b2f4ba718 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/Notification.java @@ -0,0 +1,67 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.util.Date; + +/** + * Persisted record of a notification that was sent (or attempted) to a user. + * Backs the "notification list with unread count" feature. + */ +@Data +@Entity +@Table(name = "notification") +public class Notification { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "app_type") + private String appType; + + @Column(name = "sender_user_id") + private Integer senderUserId; + + @Column(name = "receiver_user_id", nullable = false) + private Integer receiverUserId; + + @Column(name = "title") + private String title; + + @Column(name = "body") + private String body; + + @Column(name = "notification_type") + private String notificationType; + + @Column(name = "nav_id") + private String navId; + + @Column(name = "redirect") + private String redirect; + + @Column(name = "priority") + private String priority; + + @Column(name = "is_read", nullable = false) + private boolean isRead = false; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date", nullable = false, updatable = false) + private Date createdDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "read_date") + private Date readDate; + + @PrePersist + protected void onCreate() { + this.createdDate = new Date(); + if (!isRead) { + this.readDate = null; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/UserFcmTokenData.java b/src/main/java/com/iemr/flw/domain/iemr/UserFcmTokenData.java new file mode 100644 index 000000000..dd56c5b28 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/UserFcmTokenData.java @@ -0,0 +1,23 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.sql.Timestamp; + +import static jakarta.persistence.GenerationType.IDENTITY; + +@Entity +@Table(name = "user_fcm_tokens", schema = "db_iemr") +@Data +public class UserFcmTokenData { + @Id + @GeneratedValue(strategy = IDENTITY) + private int id; + @Column(name = "user_id") + private Integer userId; + @Column(name = "token") + private String token; + @Column(name = "updated_at") + private Timestamp updatedAt; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/NotificationDTO.java b/src/main/java/com/iemr/flw/dto/iemr/NotificationDTO.java new file mode 100644 index 000000000..b20dd7155 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/NotificationDTO.java @@ -0,0 +1,13 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +import java.util.Map; + +@Data +public class NotificationDTO { + private String title; + private String body; + private String token; + private Map data; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/NotificationListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/NotificationListDTO.java new file mode 100644 index 000000000..2e94be29f --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/NotificationListDTO.java @@ -0,0 +1,24 @@ +package com.iemr.flw.dto.iemr; + +import com.iemr.flw.domain.iemr.Notification; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * Response payload for the "list notifications" endpoint. + * Bundles the page of notifications together with the receiver's + * total unread count so the client can update a badge in one call. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class NotificationListDTO { + private List notifications; + private long unreadCount; + private long totalCount; + private int page; + private int size; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/SendNotificationRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/SendNotificationRequestDTO.java new file mode 100644 index 000000000..b1551ab3c --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/SendNotificationRequestDTO.java @@ -0,0 +1,18 @@ +package com.iemr.flw.dto.iemr; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SendNotificationRequestDTO { + private String appType; + private String topic; + private String title; + private String body; + private String redirect; + private String notificationType; + private Integer receiverId; +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 8c21f0e9f..81dc1865f 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -71,7 +71,8 @@ IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId( @Query("SELECT " + "SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), " + "SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), " + - "SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END) " + + "SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), " + + "SUM(CASE WHEN record.approvalStatus = 104 THEN 1 ELSE 0 END) " + "FROM IncentiveActivityRecord record " + "WHERE record.ashaId = :ashaId " + "AND record.isClaimed = true " + @@ -83,6 +84,24 @@ List getStatusCountByAshaId( @Param("endDate") Timestamp endDate); + @Query("SELECT " + + "SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), " + + "SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), " + + "SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), " + + "SUM(CASE WHEN record.approvalStatus = 104 THEN 1 ELSE 0 END) " + + "FROM IncentiveActivityRecord record " + + "WHERE record.ashaId = :ashaId " + + "AND record.isClaimed = true " + + "AND record.isDefaultActivity = true " + + "AND record.createdDate >= :startDate " + + "AND record.createdDate < :endDate") + List getStatusCountByAshaIdOfDefaultActivity( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + + @Query("SELECT COALESCE(SUM(record.amount), 0) " + "FROM IncentiveActivityRecord record " + "JOIN IncentiveActivity master ON record.activityId = master.id " + @@ -99,6 +118,35 @@ Long getTotalAmountByAsha( @Param("approvalStatus") Integer approvalStatus, @Param("stateCode") Integer stateCode); + @Query("SELECT COALESCE(SUM(record.amount), 0) " + + "FROM IncentiveActivityRecord record " + + "JOIN IncentiveActivity master ON record.activityId = master.id " + + "WHERE record.ashaId = :ashaId " + + "AND master.state = :stateCode " + + "AND record.isClaimed = true " + + "AND record.isDefaultActivity = true " + + "AND record.startDate >= :fromDate " + + "AND record.endDate <= :toDate " + + "AND (:approvalStatus = 0 OR record.approvalStatus = :approvalStatus)") + Long getDefaultActivityTotalAmountByAsha( + @Param("ashaId") Integer ashaId, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate, + @Param("approvalStatus") Integer approvalStatus, + @Param("stateCode") Integer stateCode); + + + @Query("SELECT record " + + "FROM IncentiveActivityRecord record " + + "WHERE record.ashaId = :ashaId " + + "AND record.isClaimed = true " + + "AND record.startDate <= :toDate " + + "AND record.isDefaultActivity = true " + + "AND record.endDate >= :fromDate") + List getDefalutRecordsByAsha( + @Param("ashaId") Integer ashaId, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate); @Query("SELECT record " + "FROM IncentiveActivityRecord record " + @@ -134,6 +182,53 @@ int updateApprovalStatusByAshaAndDateRange( @Param("ashaSupervisorUserName") String ashaSupervisorUserName); + @Modifying + @Transactional + @Query(""" +UPDATE IncentiveActivityRecord iar +SET + iar.approvalStatus = :approvalStatus, + + iar.verifiedByUserId = + CASE + WHEN iar.isDefaultActivity = false + THEN :ashaSupervisorUserId + ELSE iar.verifiedByUserId + END, + + iar.verifiedByUserName = + CASE + WHEN iar.isDefaultActivity = false + THEN :ashaSupervisorUserName + ELSE iar.verifiedByUserName + END, + + iar.approvalDate = + CASE + WHEN iar.isDefaultActivity = false + THEN :approvalDate + ELSE iar.approvalDate + END, + + iar.reason = NULL, + iar.otherReason = NULL + +WHERE iar.ashaId = :ashaId +AND iar.isClaimed = true +AND iar.createdDate >= :startDate +AND iar.createdDate < :endDate +""") + int updateApprovalStatusByAshaAndDateRangeForDefaultActivity( + @Param("ashaId") Integer ashaId, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate, + @Param("approvalDate") Timestamp approvalDate, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName + ); + + @Modifying @Transactional @Query("UPDATE IncentiveActivityRecord iar " diff --git a/src/main/java/com/iemr/flw/repo/iemr/NotificationRepository.java b/src/main/java/com/iemr/flw/repo/iemr/NotificationRepository.java new file mode 100644 index 000000000..c269c97c7 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/NotificationRepository.java @@ -0,0 +1,35 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.Notification; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; + +public interface NotificationRepository extends JpaRepository { + + /** Paged list for a receiver, newest first. */ + Page findByReceiverUserIdOrderByCreatedDateDesc(Integer receiverUserId, Pageable pageable); + + /** Cheap count for badge display. */ + long countByReceiverUserIdAndIsReadFalse(Integer receiverUserId); + + /** Mark a single notification as read. */ + @Modifying + @Transactional + @Query("UPDATE Notification n SET n.isRead = true, n.readDate = :readDate " + + "WHERE n.id = :id") + int markAsRead(@Param("id") Long id, @Param("readDate") Date readDate); + + /** Mark every unread notification for a user as read. */ + @Modifying + @Transactional + @Query("UPDATE Notification n SET n.isRead = true, n.readDate = :readDate " + + "WHERE n.receiverUserId = :receiverUserId AND n.isRead = false") + int markAllAsRead(@Param("receiverUserId") Integer receiverUserId, @Param("readDate") Date readDate); +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java index a56587776..d1a1f6611 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -20,22 +20,51 @@ public interface SupervisorDashboardRepo extends JpaRepository getAshaIdsBySupervisor(@Param("supervisorUserID") Integer supervisorUserID); + @Query(value = "SELECT DISTINCT usrm.FacilityID " + + "FROM m_UserServiceRoleMapping usrm " + + "WHERE usrm.UserID = :userID AND usrm.Deleted = false " + + "AND usrm.FacilityID IS NOT NULL", nativeQuery = true) + List getUserFacilityIDs(@Param("userID") Integer userID); + // Get ASHAs with facility info for a supervisor - @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + @Query(value = "SELECT DISTINCT u.UserID, u.FirstName, u.LastName, " + + "COALESCE(u.EmployeeID,'') AS employeeID, " + "f.FacilityID, f.FacilityName, " + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName, " - + "COALESCE(u.AgentID,'') AS agentID, " - + "COALESCE(u.EmergencyContactNo,'') AS mobile, " - + "COALESCE(g.GenderName,'') AS gender " + + "COALESCE(u.ContactNo,'') AS mobile " + "FROM asha_supervisor_mapping asm " - + "JOIN m_User u ON u.UserID = asm.ashaUserID AND u.Deleted = false " - + "JOIN m_facility f ON f.FacilityID = asm.facilityID AND f.Deleted = false " + + "JOIN m_User u ON u.UserID = asm.ashaUserID " + + "JOIN m_facility f ON f.FacilityID = asm.facilityID " + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " - + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + "WHERE asm.supervisorUserID = :supervisorUserID " - + "AND asm.deleted = false", nativeQuery = true) + + "AND asm.deleted = false AND u.Deleted = false AND f.Deleted = false", nativeQuery = true) List getAshasWithFacilityInfo(@Param("supervisorUserID") Integer supervisorUserID); + + @Query(value = "SELECT DISTINCT u.UserID, u.FirstName, u.LastName, " + + "COALESCE(u.EmployeeID,'') AS employeeID, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName, " + + "COALESCE(u.ContactNo,'') AS mobile " + + "FROM m_UserServiceRoleMapping usrm " + + "JOIN m_User u ON u.UserID = usrm.UserID " + + "JOIN m_Role r ON r.RoleID = usrm.RoleID " + + "JOIN m_facility f ON f.FacilityID = usrm.FacilityID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE usrm.FacilityID IN :facilityIDs " + + "AND r.RoleName = 'ASHA' " + + "AND usrm.Deleted = false AND u.Deleted = false AND f.Deleted = false", nativeQuery = true) + List getAshaListByFacilities(@Param("facilityIDs") List facilityIDs); + + @Query(value = """ + SELECT asm.supervisorUserID + FROM asha_supervisor_mapping asm + WHERE asm.ashaUserID = :ashaUserID + AND asm.deleted = false + LIMIT 1 + """, nativeQuery = true) + Integer getSupervisorUserIdByAshaId(@Param("ashaUserID") Integer ashaUserID); + // Unclaimed incentive count per ASHA @Query(value = "SELECT iar.asha_id, " + "COUNT(*) AS unclaimedCount " @@ -91,6 +120,24 @@ List getIncentiveStatusByAshaIds( @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate); + @Query(value = "SELECT iar.asha_id, " + + "COUNT(*) AS totalRecords, " + + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " + + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " + + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN (:ashaIds) " + + "AND iar.created_date >= :startDate " + + "AND iar.is_claimed = true " + + "AND iar.is_default_activity = true " + + "AND iar.created_date < :endDate " + + "GROUP BY iar.asha_id", + nativeQuery = true) + List getDefaultIncentiveStatusByAshaIds( + @Param("ashaIds") List ashaIds, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + // Incentive activity history per ASHA (recent records) @Query(value = "SELECT iar.asha_id, iar.name AS activityName, " + "iar.amount, iar.is_eligible, iar.created_date " diff --git a/src/main/java/com/iemr/flw/repo/iemr/UserFcmTokenRepo.java b/src/main/java/com/iemr/flw/repo/iemr/UserFcmTokenRepo.java new file mode 100644 index 000000000..3426f5a25 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/UserFcmTokenRepo.java @@ -0,0 +1,34 @@ +/* +* 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/. +* +/* +* AMRIT – Accessible Medical Records via Integrated Technology +*/ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.UserFcmTokenData; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserFcmTokenRepo extends JpaRepository { + UserFcmTokenData findByUserId(Integer userId); +} diff --git a/src/main/java/com/iemr/flw/service/IncentiveService.java b/src/main/java/com/iemr/flw/service/IncentiveService.java index 8b2e46001..01da2431e 100644 --- a/src/main/java/com/iemr/flw/service/IncentiveService.java +++ b/src/main/java/com/iemr/flw/service/IncentiveService.java @@ -14,7 +14,7 @@ public interface IncentiveService { String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO); String getAllIncentivesByUserId(GetBenRequestHandler requestDTO); - String getAllIncentivesGroupedSummary(GetBenRequestHandler requestDTO); + String getAllIncentivesGroupedSummary(GetBenRequestHandler requestDTO,Integer userId); String getAllIncentivesGroupedActivity(GetBenRequestHandler requestDTO); String updateIncentive(PendingActivityDTO pendingActivityDTO); diff --git a/src/main/java/com/iemr/flw/service/NotificationService.java b/src/main/java/com/iemr/flw/service/NotificationService.java new file mode 100644 index 000000000..4d561b517 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/NotificationService.java @@ -0,0 +1,14 @@ +package com.iemr.flw.service; + +import com.iemr.flw.dto.iemr.NotificationListDTO; + +public interface NotificationService { + public String sendNotification(String appType, String topic, String title, String body, String redirect,String notificationType,Integer reciverID); + NotificationListDTO getNotifications(Integer receiverUserId); + + Long getUnreadCount(Integer receiverUserId); + + boolean markAsRead(Long notificationId); + + int markAllAsRead(Integer receiverUserId); +} diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 4903e1fc3..e65e0f53e 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -899,8 +899,6 @@ private void checkAndAddHbyncIncentives(List hbycList) { private void checkAndAddHbncIncentives(List hbncVisits, Integer userId) { Integer stateCode = userService.getUserDetail(userId).getStateId(); - List pncVisits = pncVisitRepo.getPNCForPW(userRepo.getUserNamedByUserId(userId)); - List ancVisits = ancVisitRepo.getANCForPW(userRepo.getUserNamedByUserId(userId)); hbncVisits.forEach(hbncVisit -> { Long benId = hbncVisit.getBeneficiaryId(); if (stateCode.equals(StateCode.AM.getStateCode())) { @@ -911,43 +909,7 @@ private void checkAndAddHbncIncentives(List hbncVisits, Integer userI } - pncVisits.forEach(pncVisit -> { - Long hbncHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(hbncVisit.getBeneficiaryId())).get(0).getHouseoldId(); - Long houseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(pncVisit.getBenId())).get(0).getHouseoldId(); - - if (hbncHouseHoldId.equals(houseHoldId)) { - if (hbncVisit.getVisit_day().equals("42th Day")) { - if (!ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { - if (ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getIsHrpConfirmed()) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, pncVisit.getBenId(), visitActivityCH, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); - } - } - if (!pncVisitRepo.findByBenId(pncVisit.getBenId()).isEmpty()) { - if (!pncVisitRepo.findByBenId(pncVisit.getBenId()).get(0).getMotherDangerSign().isEmpty()) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, pncVisit.getBenId(), visitActivityCH, "HIGH_RISK_POSTPARTUM_CARE"); - } - } - } - } - }); - - ancVisits.forEach(ancVisit -> { - Long hbncHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(hbncVisit.getBeneficiaryId())).get(0).getHouseoldId(); - Long ancHouseHoldId = beneficiaryRepo.getDetailsByRegID(beneficiaryRepo.getRegIDFromBenId(ancVisit.getBenId())).get(0).getHouseoldId(); - - if (hbncHouseHoldId.equals(ancHouseHoldId)) { - if (hbncVisit.getVisit_day().equals("42th Day")) { - if (!ancVisitRepo.findByBenId(ancVisit.getBenId()).isEmpty()) { - if (ancVisitRepo.findByBenId(ancVisit.getBenId()).get(0).getIsHrpConfirmed()) { - IncentiveActivity visitActivityANC = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, ancVisit.getBenId(), visitActivityANC, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); - } - } - } - } - }); + logger.info("getDischarged_from_sncu" + hbncVisit.getDischarged_from_sncu()); @@ -968,25 +930,10 @@ private void checkAndAddHbncIncentives(List hbncVisits, Integer userI } if (stateCode.equals(StateCode.CG.getStateCode())) { - if (hbncVisit.getVisit_day().equals("42th Day")) { - if (!ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { - if (ancVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getIsHrpConfirmed() && pncVisitRepo.findByBenId(hbncVisit - .getBeneficiaryId()).get(0).getPncPeriod().toString().equals("42")) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); - - createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HIGH_RISK_POSTPARTUM_HEALTH_CHECK"); - - } - } - if (!pncVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).isEmpty()) { - if (!pncVisitRepo.findByBenId(hbncVisit.getBeneficiaryId()).get(0).getMotherDangerSign().isEmpty() && pncVisitRepo.findByBenId(hbncVisit - .getBeneficiaryId()).get(0).getPncPeriod().toString().equals("42")) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); - - createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HIGH_RISK_POSTPARTUM_CARE"); + if (hbncVisit.getVisit_day().equals("42nd Day")) { + IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.ACTIVITY.getDisplayName()); + createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HBNC_0_42_DAYS"); - } - } } } diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index 3170deba0..f6769fbd8 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -151,7 +151,7 @@ public void checkAndAddJsyIncentive(List delOutList) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityAM); } - if (institutionalDeliveryActivityCH != null) { + if (institutionalDeliveryActivityCH != null && placeOfDelivery.toLowerCase().equals("Government Hospital")) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityCH); } } diff --git a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java index e6a69ba22..35746b2f8 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java @@ -301,20 +301,18 @@ public String saveLeprosy(LeprosyDTO diseaseControlDTO) { diseaseControlData.setUserId(diseaseControlDTO.getUserId()); } ScreeningLeprosy screeningLeprosy = diseaseLeprosyRepository.save(saveLeprosyData(diseaseControlData)); - if(screeningLeprosy.getIsConfirmed()){ - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForIdentificationLeprosy( - screeningLeprosy.getBenId(), - screeningLeprosy.getHomeVisitDate(), - screeningLeprosy.getHomeVisitDate(), - diseaseControlDTO.getUserId()); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); - } + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForIdentificationLeprosy( + screeningLeprosy.getBenId(), + screeningLeprosy.getHomeVisitDate(), + screeningLeprosy.getHomeVisitDate(), + diseaseControlDTO.getUserId()); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); } return "Data add successfully"; diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index f109c88a8..8f814af20 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -3,18 +3,17 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.iemr.flw.domain.identity.RMNCHMBeneficiarydetail; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; import com.iemr.flw.masterEnum.IncentiveApprovalStatus; -import com.iemr.flw.masterEnum.IncentiveName; import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.IncentiveService; import com.iemr.flw.service.MaaMeetingService; +import com.iemr.flw.service.NotificationService; import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; import jakarta.persistence.criteria.CriteriaBuilder; @@ -30,11 +29,10 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import java.math.BigInteger; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; +import java.time.Month; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -85,6 +83,12 @@ public class IncentiveServiceImpl implements IncentiveService { private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + @Autowired + private NotificationService notificationService; + + @Autowired + private SupervisorDashboardRepo dashboardRepo; + // ================= MASTER SAVE ================= @@ -329,8 +333,8 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { // ================= GROUPED SUMMARY ================= @Override - public String getAllIncentivesGroupedSummary(GetBenRequestHandler request) { - + public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Integer userId) { + String roleName = userService.getUserDetail(userId).getRoleName(); LocalDate start = LocalDate.of(request.getYear(), request.getMonth(), 1); LocalDate end = start.withDayOfMonth(start.lengthOfMonth()); @@ -361,9 +365,23 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request) { : incentivesRepo.findValidActivityIds(activityIds, false); // Filter records based on valid activity IDs - records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) - .collect(Collectors.toList()); + if(isCG){ + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) + .collect(Collectors.toList()); + }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) ){ + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .collect(Collectors.toList()); + } + + }else { + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .collect(Collectors.toList()); + } + Map> grouped = records.stream().collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); @@ -385,14 +403,29 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request) { .sum(); Map map = new HashMap<>(); - map.put("activityId", activityId); - map.put("activityDec", activity.getDescription()); - map.put("groupName", activity.getGroup()); - map.put("claimCount", list.size()); - map.put("totalAmount", total); - map.put("amount", activity.getRate()); + if(isCG){ + map.put("activityId", activityId); + map.put("activityDec", activity.getDescription()); + map.put("groupName", activity.getGroup()); + map.put("isDefault", activity.getIsDefaultActivity()); + map.put("claimCount", list.size()); + map.put("totalAmount", total); + map.put("amount", activity.getRate()); + + }else { + map.put("activityId", activityId); + map.put("activityDec", activity.getDescription()); + map.put("groupName", activity.getGroup()); + map.put("claimCount", list.size()); + map.put("totalAmount", total); + map.put("amount", activity.getRate()); + + } result.add(map); + + + } return new Gson().toJson(result); @@ -554,10 +587,12 @@ public String updateIncentive(PendingActivityDTO pendingActivityDTO) { // ================= UPDATE CLAIM ================= @Transactional public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boolean isClaimed, String token) { + String title = null; try { LocalDate start = LocalDate.of(year, month, 1); LocalDate end = start.plusMonths(1); + int updated = recordRepo.updateClaimStatusByAshaAndDateRange( ashaId, isClaimed, @@ -565,6 +600,42 @@ public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boo Timestamp.valueOf(start.atStartOfDay()), Timestamp.valueOf(end.atStartOfDay()) ); + if(updated>0){ + Map data = new HashMap<>(); + data.put("notification_type", "INCENTIVE_APPROVAL"); + data.put("nav_id", "INCENTIVE_HISTORY"); + data.put("sender_user_id", String.valueOf(ashaId)); + data.put("receiver_user_id", String.valueOf(ashaId)); + data.put("month", String.valueOf(month)); + data.put("year", String.valueOf(year)); + data.put("approval_status", String.valueOf(102)); + data.put("priority", "HIGH"); + title = "Incentive Approved"; + + + + if (isClaimed) { + String body = "Your incentive Successfully claimed for month of" + Month.of(month).name() + " " + year; + notificationService.sendNotification( + "FLW","NA" , + title, + body, + "INCENTIVE_CLAIMED","INCENTIVE",ashaId + ); + } + if (isClaimed) { + String body = userService.getUserDetail(ashaId).getName()+" Successfully claimed Incentive for month of " + Month.of(month).name() + " " + year; + notificationService.sendNotification( + "FLW","NA" , + title, + body, + "INCENTIVE_CLAIMED","INCENTIVE",dashboardRepo.getSupervisorUserIdByAshaId(ashaId) + ); + } + + + + } return updated > 0 ? "Success" : "No records"; diff --git a/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java b/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java index 21d0da458..39314c8ff 100644 --- a/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java +++ b/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java @@ -14,8 +14,6 @@ public class NotificationSchedulerService { final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - @Autowired - private NotificationService notificationService; @Autowired EmployeeMasterInter employeeMasterInter; @@ -43,13 +41,6 @@ public void triggerAncRemindersForAllAsha() { String topic = "All"; // or some user/topic identifier String title = "ANC Reminder"; - notificationService.sendNotification( - appType, - topic, - title, - body, - redirectPath - ); } diff --git a/src/main/java/com/iemr/flw/service/impl/NotificationService.java b/src/main/java/com/iemr/flw/service/impl/NotificationService.java deleted file mode 100644 index 838ff3ac8..000000000 --- a/src/main/java/com/iemr/flw/service/impl/NotificationService.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.iemr.flw.service.impl; - -import com.google.gson.Gson; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import java.util.HashMap; -import java.util.Map; - -@Service -public class NotificationService { - final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - - - private String NOTIFICATION_URL = "https://uatamrit.piramalswasthya.org/common-api/firebaseNotification/sendNotification"; - - public String sendNotification(String appType, String topic, String title, String body, String redirect) { - String authHeader = null; - String jwtToken = null; - - // Check if we have HTTP request context - ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - if (attributes != null) { - HttpServletRequest httpServletRequest = attributes.getRequest(); - - authHeader = httpServletRequest.getHeader("Authorization"); - - if (httpServletRequest.getCookies() != null) { - for (Cookie cookie : httpServletRequest.getCookies()) { - if ("Jwttoken".equals(cookie.getName())) { - jwtToken = cookie.getValue(); - } - } - } - } - - // If no request context, set default (for scheduler/startup use) - if (authHeader == null) { - authHeader = "Bearer DEFAULT_TOKEN_IF_REQUIRED"; // or leave null if API allows - } - if (jwtToken == null) { - jwtToken = "DEFAULT_JWT_IF_REQUIRED"; - } - - RestTemplate restTemplate = new RestTemplate(); - MultiValueMap headers = new LinkedMultiValueMap<>(); - headers.add("Content-Type", "application/json"); -// headers.add("AUTHORIZATION", authHeader); -// headers.add("Cookie", "Jwttoken=" + jwtToken); - - Map requestBody = new HashMap<>(); - requestBody.put("appType", appType); - requestBody.put("token", topic); - requestBody.put("title", title); - requestBody.put("body", body); - - Map dataMap = new HashMap<>(); - dataMap.put("NotificationTypeId", redirect); - requestBody.put("data", dataMap); - - String jsonRequest = new Gson().toJson(requestBody); - - HttpEntity request = new HttpEntity<>(jsonRequest, headers); - - ResponseEntity response = restTemplate.exchange(NOTIFICATION_URL, HttpMethod.POST, request, String.class); - - return response.getBody(); - } -} diff --git a/src/main/java/com/iemr/flw/service/impl/NotificationServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/NotificationServiceImpl.java new file mode 100644 index 000000000..8a157cb2f --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/NotificationServiceImpl.java @@ -0,0 +1,222 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.Notification; +import com.iemr.flw.domain.iemr.UserFcmTokenData; +import com.iemr.flw.dto.iemr.NotificationListDTO; +import com.iemr.flw.repo.iemr.NotificationRepository; +import com.iemr.flw.repo.iemr.UserFcmTokenRepo; +import com.iemr.flw.service.NotificationService; +import com.iemr.flw.utils.JwtUtil; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Service +public class NotificationServiceImpl implements NotificationService { + final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Value("${common-api-base-url}") + private String commonApiBaseUrl; + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private NotificationRepository notificationRepository; + + @Autowired + private UserFcmTokenRepo userFcmTokenRepo; + + + private String NOTIFICATION_URL = "/firebaseNotification/sendNotification"; + + public String sendNotification(String appType, String topic, String title, + String body, String redirect, + String notificationType, Integer receiverId) { + + logger.info("Initiating notification. appType={}, receiverId={}, type={} , commonApiBaseUrl={}", + appType, receiverId, notificationType,commonApiBaseUrl); + + try { + String authHeader = null; + ServletRequestAttributes attributes = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + + if (attributes != null) { + HttpServletRequest request = attributes.getRequest(); + authHeader = request.getHeader("jwtToken"); + } + + Integer senderId = jwtUtil.extractUserId(authHeader); + + logger.debug("Sender Id: {}", senderId); + + + UserFcmTokenData tokenData = userFcmTokenRepo.findByUserId(receiverId); + + if (tokenData == null) { + logger.warn("FCM token not found for receiverId={}", receiverId); + return "FCM token not found."; + } + + String token = tokenData.getToken(); + + + + RestTemplate restTemplate = new RestTemplate(); + + MultiValueMap headers = new LinkedMultiValueMap<>(); + headers.add("Content-Type", "application/json"); + headers.add("jwtToken", authHeader); + + Map requestBody = new HashMap<>(); + requestBody.put("appType", appType); + requestBody.put("token", token); + requestBody.put("title", title); + requestBody.put("body", body); + + Map dataMap = new HashMap<>(); + dataMap.put("notification_id", notificationType); + dataMap.put("notification_type", notificationType); + dataMap.put("nav_id", redirect); + dataMap.put("sender_user_id", senderId); + dataMap.put("receiver_user_id", receiverId); + dataMap.put("priority", "HIGH"); + dataMap.put("redirect", redirect); + + requestBody.put("data", dataMap); + + String jsonRequest = new Gson().toJson(requestBody); + + logger.debug("Notification request payload: {}", NOTIFICATION_URL); + HttpEntity request = new HttpEntity<>(jsonRequest, headers); + + ResponseEntity response = restTemplate.exchange( + commonApiBaseUrl+NOTIFICATION_URL, + HttpMethod.POST, + request, + String.class); + + logger.info("Notification API response. Status={}, Body={}", + response.getStatusCode(), + response.getBody()); + + saveNotificationRecord(appType, senderId, receiverId, title, body, + notificationType, "INCENTIVE_APPROVAL", redirect, "HIGH"); + + logger.info("Notification record saved successfully. receiverId={}", receiverId); + + return response.getBody(); + + } catch (HttpClientErrorException | HttpServerErrorException ex) { + + logger.error("Notification API failed. Status={}, Response={}", + ex.getStatusCode(), + ex.getResponseBodyAsString(), + ex); + + throw ex; + + } catch (Exception ex) { + + logger.error("Unexpected error while sending notification. receiverId={}, type={}", + receiverId, + notificationType, + ex); + + throw new RuntimeException("Failed to send notification.", ex); + } + } + + + private void saveNotificationRecord(String appType, Integer senderUserId, Integer receiverUserId, + String title, String body, String notificationType, + String navId, String redirect, String priority) { + try { + Notification notification = new Notification(); + notification.setAppType(appType); + notification.setSenderUserId(senderUserId); + notification.setReceiverUserId(receiverUserId); + notification.setTitle(title); + notification.setBody(body); + notification.setNotificationType(notificationType); + notification.setNavId(navId); + notification.setRedirect(redirect); + notification.setPriority(priority); + notification.setRead(false); + notificationRepository.save(notification); + } catch (Exception e) { + logger.error("Failed to persist notification record for receiver {}", receiverUserId, e); + } + } + + /** Paged list of a user's notifications, newest first, with unread count attached. */ + public NotificationListDTO getNotifications(Integer receiverUserId) { + + int page = 0; // First page + int size = 20; // Records per page + + Pageable pageable = PageRequest.of( + page, + size, + Sort.by(Sort.Direction.DESC, "createdDate") + ); + + Page result = + notificationRepository.findByReceiverUserIdOrderByCreatedDateDesc( + receiverUserId, + pageable + ); + + long unreadCount = + notificationRepository.countByReceiverUserIdAndIsReadFalse(receiverUserId); + + return new NotificationListDTO( + result.getContent(), + unreadCount, + result.getTotalElements(), + result.getNumber(), + result.getSize() + ); + } + + /** + * Lightweight call for a badge — no list, just the count. + */ + public Long getUnreadCount(Integer receiverUserId) { + return notificationRepository.countByReceiverUserIdAndIsReadFalse(receiverUserId); + } + + /** Marks a single notification read. Returns true if a row was updated. */ + public boolean markAsRead(Long notificationId) { + int updated = notificationRepository.markAsRead(notificationId, new Date()); + return updated > 0; + } + + /** Marks all of a user's notifications read. Returns the number updated. */ + public int markAllAsRead(Integer receiverUserId) { + return notificationRepository.markAllAsRead(receiverUserId, new Date()); + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 771810e20..bf164baaf 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -3,18 +3,16 @@ import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.time.Month; +import java.util.*; import java.util.stream.Collectors; import com.iemr.flw.domain.iemr.IncentiveActivityRecord; import com.iemr.flw.dto.iemr.UserServiceRoleDTO; import com.iemr.flw.masterEnum.IncentiveApprovalStatus; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.NotificationService; import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; import org.json.JSONArray; @@ -50,9 +48,14 @@ public class SupervisorDashboardServiceImpl implements SupervisorDashboardServic @Autowired private UserService userService; + @Autowired + private NotificationService notificationService; + @Override public String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year) { JSONObject result = new JSONObject(); + Integer stateId = userService.getUserDetail(supervisorUserID).getStateId(); + String rollName = userService.getUserDetail(supervisorUserID).getRoleName(); // 1. Supervisor user details List supervisorRows = dashboardRepo.getSupervisorUserDetails(supervisorUserID); @@ -66,28 +69,76 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In supervisor.put("gender", str(sRow[5]).isEmpty() ? JSONObject.NULL : str(sRow[5])); result.put("supervisor", supervisor); } + logger.info("Supervisor id"+supervisorUserID); // 2. Get all ASHAs with facility info - List ashaRows = dashboardRepo.getAshasWithFacilityInfo(supervisorUserID); + logger.info("Fetching ASHA details for supervisorUserID: {}", supervisorUserID); + + + + List ashaRows; + + if ("ANM".equalsIgnoreCase(rollName) || "CHO".equalsIgnoreCase(rollName)) { + + List facilityIDs = + facilityLoginRepo.getUserFacilityIDs(supervisorUserID); + + ashaRows = + facilityLoginRepo.getAshaListByFacilities(facilityIDs); + + } else { + + ashaRows = + dashboardRepo.getAshasWithFacilityInfo(supervisorUserID); + + } + if (ashaRows == null || ashaRows.isEmpty()) { + logger.warn("No ASHA records found for supervisorUserID: {}", supervisorUserID); + result.put("totalAshaCount", 0); result.put("incentiveSummary", buildEmptyIncentiveSummary()); result.put("facilities", new JSONArray()); + + logger.info("Returning empty dashboard response for supervisorUserID: {}", supervisorUserID); + return result.toString(); } + + // Collect distinct facility IDs and ASHA IDs + + logger.info("Processing {} ASHA records", ashaRows.size()); + Set facilityIDSet = new HashSet<>(); Set ashaIDSet = new HashSet<>(); + for (Object[] row : ashaRows) { - if (row[3] != null) - facilityIDSet.add((Integer) row[3]); + + logger.info("Complete Row: {}", Arrays.toString(row)); + + for (int i = 0; i < row.length; i++) { + logger.info("row[{}] = {} ({})", + i, + row[i], + row[i] != null ? row[i].getClass().getName() : "null"); + } + + + if (row[4] != null) + facilityIDSet.add((Integer) row[4]); + if (row[0] != null) ashaIDSet.add((Integer) row[0]); + } + List facilityIDs = new ArrayList<>(facilityIDSet); List ashaIDs = new ArrayList<>(ashaIDSet); + logger.info("Facility IDs: {}", facilityIDs); + logger.info("ASHA IDs: {}", ashaIDs); result.put("totalAshaCount", ashaIDs.size()); // 3. Location from first facility @@ -133,27 +184,68 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); logger.info("Asha ID" + ashaIDs); - List statusRows = dashboardRepo.getIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); - if (statusRows != null) { - for (Object[] sRow : statusRows) { - long verified = ((Number) sRow[2]).longValue(); - long rejected = ((Number) sRow[3]).longValue(); - long pending = ((Number) sRow[4]).longValue(); - - if (verified > 0) overallVerified += 1; - if (rejected > 0) overallRejected += 1; - if (pending > 0) overallPending += 1; + if(stateId.equals(StateCode.AM.getStateCode())){ + List statusRows = dashboardRepo.getIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); + if (statusRows != null) { + for (Object[] sRow : statusRows) { + long verified = ((Number) sRow[2]).longValue(); + long rejected = ((Number) sRow[3]).longValue(); + long pending = ((Number) sRow[4]).longValue(); + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + } } - } - List unclaimedRows = dashboardRepo.getUnclaimedCountByAshaIds(ashaIDs, startDate, endDate); - if (unclaimedRows != null) { - for (Object[] uRow : unclaimedRows) { - long count = ((Number) uRow[1]).longValue(); - if (count > 0) overallUnclaimed += 1; + List unclaimedRows = dashboardRepo.getUnclaimedCountByAshaIds(ashaIDs, startDate, endDate); + if (unclaimedRows != null) { + for (Object[] uRow : unclaimedRows) { + long count = ((Number) uRow[1]).longValue(); + if (count > 0) overallUnclaimed += 1; + } + } + }else if(stateId.equals(StateCode.CG.getStateCode())){ + if("ASHA Supervisor".equalsIgnoreCase(rollName)){ + List statusRows = dashboardRepo.getDefaultIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); + if (statusRows != null) { + for (Object[] sRow : statusRows) { + long verified = ((Number) sRow[2]).longValue(); + long rejected = ((Number) sRow[3]).longValue(); + long pending = ((Number) sRow[4]).longValue(); + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + } + } + }else if("ANM".equalsIgnoreCase(rollName)){ + List statusRows = dashboardRepo.getIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); + if (statusRows != null) { + for (Object[] sRow : statusRows) { + long verified = ((Number) sRow[2]).longValue(); + long rejected = ((Number) sRow[3]).longValue(); + long pending = ((Number) sRow[4]).longValue(); + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + } + } + } + + List unclaimedRows = dashboardRepo.getUnclaimedCountByAshaIds(ashaIDs, startDate, endDate); + if (unclaimedRows != null) { + for (Object[] uRow : unclaimedRows) { + long count = ((Number) uRow[1]).longValue(); + if (count > 0) overallUnclaimed += 1; + } } } + + } catch (Exception e) { logger.error("Error fetching incentive status: " + e.getMessage(), e); + } @@ -170,7 +262,7 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In // 7. Build facilities array with nested ASHAs Map> ashasByFacility = new HashMap<>(); for (Object[] row : ashaRows) { - Integer facID = (Integer) row[3]; + Integer facID = (Integer) row[4]; ashasByFacility.computeIfAbsent(facID, k -> new ArrayList<>()).add(row); } @@ -204,7 +296,6 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In asha.put("fullName", fullName(row[1], row[2])); asha.put("employeeId", str(row[6]).isEmpty() ? JSONObject.NULL : str(row[6])); asha.put("mobile", str(row[7]).isEmpty() ? JSONObject.NULL : str(row[7])); - asha.put("gender", str(row[8]).isEmpty() ? JSONObject.NULL : str(row[8])); ashasArray.put(asha); } @@ -218,10 +309,26 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In return result.toString(); } + + @Override public Map getAshasAtFacility(Integer supervisorId, Integer facilityId, Integer month, Integer year, Integer approvalStatusID) { + Integer supervisorstateCode = userService.getUserDetail(supervisorId).getStateId(); List rows; + LocalDate today = LocalDate.now(); + + + String roleName = userService.getUserDetail(supervisorId).getRoleName(); + + LocalDate currentMonthStartDate = LocalDate.of(year, month, 1); + LocalDate currentMonthendLocalDate = currentMonthStartDate.plusMonths(1); + + logger.info("Login user role:"+ roleName); + + boolean isCurrentMonth = + today.getYear() == year && + today.getMonthValue() == month; logger.info("approvalStatusID:" + approvalStatusID); List superVisorRow = ashaSupervisorLoginRepo.getAllMappedAshas(supervisorId); @@ -234,15 +341,36 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci Timestamp startDate = Timestamp.valueOf(startLocalDate.atStartOfDay()); Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); - if (facilityId.equals(0)) { - rows = ashaSupervisorLoginRepo.getAshasAtFacility( - supervisorId, approvalStatusID, startDate, endDate); + + + + if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { + + if (facilityId.equals(0)) { + + List facilityIDs = facilityLoginRepo.getUserFacilityIDs(supervisorId); + rows = facilityLoginRepo.getAshaListByFacilities(facilityIDs); + + } else { + + rows = facilityLoginRepo.getAshaListByFacilities( + Collections.singletonList(facilityId)); + + } + } else { - rows = ashaSupervisorLoginRepo.getAshasAtFacility( - supervisorId, facilityId, approvalStatusID, startDate, endDate); + + if (facilityId.equals(0)) { + rows = ashaSupervisorLoginRepo.getAshasAtFacility( + supervisorId, approvalStatusID, startDate, endDate); + } else { + rows = ashaSupervisorLoginRepo.getAshasAtFacility( + supervisorId, facilityId, approvalStatusID, startDate, endDate); + } + } - long overallVerified = 0, overallRejected = 0, overallPending = 0; + long overallVerified = 0, overallRejected = 0, overallPending = 0 ,overallApproved =0; String facilityName = ""; String facilityType = ""; @@ -259,23 +387,86 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci Map asha = new HashMap<>(); Integer ashaId = ((Number) row[0]).intValue(); + logger.info("ASHA_ID"+ashaId); + List countList =null; + + if(supervisorstateCode.equals(StateCode.CG.getStateCode())){ + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + countList = incentiveRecordRepo.getStatusCountByAshaIdOfDefaultActivity(ashaId, startDate, endDate); + + }else if(("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) )){ + logger.info("ASHA_ID = {}", ashaId); + logger.info("Role = {}", roleName); + + countList = incentiveRecordRepo.getStatusCountByAshaId(ashaId, startDate, endDate); + + logger.info("Count List = {}", countList); + + } + + }else if(supervisorstateCode.equals(StateCode.AM.getStateCode())){ + countList = incentiveRecordRepo.getStatusCountByAshaId(ashaId, startDate, endDate); + + } - List countList = incentiveRecordRepo.getStatusCountByAshaId(ashaId, startDate, endDate); Long totalAmount = null; if (userService.getUserDetail(ashaId) != null) { Integer stateCode = userService.getUserDetail(ashaId).getStateId(); - totalAmount = incentiveRecordRepo.getTotalAmountByAsha( - ashaId, startDate, endDate, approvalStatusID, stateCode); + if(stateCode.equals(StateCode.AM.getStateCode())){ + totalAmount = incentiveRecordRepo.getTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); + }else if(stateCode.equals(StateCode.CG.getStateCode())){ + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + + totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); + }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) ){ + totalAmount = incentiveRecordRepo.getTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); + } - } + } - List incentiveActivityRecord = - incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate) - .stream() - .filter(r -> approvalStatusID == 0 || - approvalStatusID.equals(r.getApprovalStatus())) - .collect(Collectors.toList()); + } + Integer stateCode = userService.getUserDetail(ashaId).getStateId(); + + + List incentiveActivityRecord = null; + if(stateCode.equals(StateCode.AM.getStateCode())){ + List dbRecords = + incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate); + incentiveActivityRecord= dbRecords + .stream() + .filter(r -> approvalStatusID == 0 || + approvalStatusID.equals(r.getApprovalStatus())) + .collect(Collectors.toList()); + }else if(stateCode.equals(StateCode.CG.getStateCode())){ + List dbRecords = + incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate); + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + incentiveActivityRecord = dbRecords.stream() + .filter(r -> approvalStatusID == 0 || + approvalStatusID.equals(r.getApprovalStatus()) && r.getIsDefaultActivity() && isWithin24Hours(r.getCalimedDate())) + .collect(Collectors.toList()); + }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { + incentiveActivityRecord = dbRecords.stream() + .filter(r -> approvalStatusID == 0 || + approvalStatusID.equals(r.getApprovalStatus()) && isAfter24Hours(r.getCreatedDate())) + .peek(r -> { + if (isAfter24Hours(r.getCreatedDate()) + && r.getApprovalStatus().equals(102)) { + r.setApprovalStatus(104); + } + }) + .collect(Collectors.toList()); + } + + + logger.info("CG - Records after approvalStatus filter: {}", incentiveActivityRecord.size()); + + } + logger.info("Final incentiveActivityRecord count: {}", incentiveActivityRecord.size()); List> activityList = new ArrayList<>(); for (IncentiveActivityRecord record : incentiveActivityRecord) { Map activity = new HashMap<>(); @@ -285,14 +476,16 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci activity.put("approvalStatus", record.getApprovalStatus()); if(record.getVerifiedByUserId()!=null){ activity.put("verifiedByUserName", userService.getUserDetail(record.getVerifiedByUserId()).getName()); + activity.put("verifiedByUserId", record.getVerifiedByUserId()); + UserServiceRoleDTO roles = userService.getUserDetail(record.getVerifiedByUserId()); + activity.put("role", (roles != null ) ? roles.getRoleName() : null); + } - activity.put("verifiedByUserId", record.getVerifiedByUserId()); activity.put("isClaimed", record.getIsClaimed()); activity.put("claimedDate", record.getCalimedDate()); - UserServiceRoleDTO roles = userService.getUserDetail(record.getVerifiedByUserId()); - activity.put("role", (roles != null ) ? roles.getRoleName() : null); + activityList.add(activity); } @@ -308,21 +501,24 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci asha.put("totalAmount", totalAmount); asha.put("activities", activityList); - long pending = 0, verified = 0, rejected = 0; + long pending = 0, verified = 0, rejected = 0 ,approved =0; if (countList != null && !countList.isEmpty()) { Object[] counts = countList.get(0); verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; pending = counts[1] != null ? ((Number) counts[1]).longValue() : 0; rejected = counts[2] != null ? ((Number) counts[2]).longValue() : 0; + approved = counts[3] != null ? ((Number) counts[3]).longValue() : 0; } if (verified > 0) overallVerified += 1; if (rejected > 0) overallRejected += 1; if (pending > 0) overallPending += 1; + if (approved > 0) overallApproved += 1; asha.put("pending", pending); asha.put("verified", verified); asha.put("rejected", rejected); + asha.put("approved", approved); int approvalStatus = 0; @@ -347,6 +543,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci approvalStatus.put("verified", overallVerified); approvalStatus.put("pending", overallPending); approvalStatus.put("rejected", overallRejected); + approvalStatus.put("approved", overallApproved); response.put("approvalStatus", approvalStatus); response.put("data", ashaList); @@ -355,6 +552,24 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci return response; } + private boolean isAfter24Hours(Timestamp claimedDate) { + if (claimedDate == null) { + return false; + } + + long diff = System.currentTimeMillis() - claimedDate.getTime(); + return diff >= 24 * 60 * 60 * 1000L; + } + private boolean isWithin24Hours(Timestamp claimedDate) { + if (claimedDate == null) { + return false; + } + + long diff = System.currentTimeMillis() - claimedDate.getTime(); + return diff <= 24 * 60 * 60 * 1000L; + } + + private String getGroupNameByState(Integer stateCode) { switch (stateCode) { case 5: @@ -374,6 +589,8 @@ public int updateApprovalStatus(Integer ashaId, String otherReason, String token) { try { + String title = null; + String body = null; Timestamp approvalDate = Timestamp.valueOf(LocalDateTime.now()); LocalDate startLocalDate = LocalDate.of(year, month, 1); @@ -384,32 +601,62 @@ public int updateApprovalStatus(Integer ashaId, Integer ashaSupervisorUserId = jwtUtil.extractUserId(token); logger.info("Asha Supervisor User Id : {}", ashaSupervisorUserId); - String ashaSupervisorUsername = userService.getUserDetail(ashaSupervisorUserId).getUserName(); + UserServiceRoleDTO ashaSupervisorDetails = userService.getUserDetail(ashaSupervisorUserId); - if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { - int totalUpdated = 0; + int updatedCount = 0; - totalUpdated += incentiveRecordRepo.updateApprovalStatusById( + if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { + updatedCount = incentiveRecordRepo.updateApprovalStatusById( approvalStatus, ashaSupervisorUserId, - ashaSupervisorUsername, + ashaSupervisorDetails.getUserName(), reason, approvalDate, otherReason ); + } else { + + if (ashaSupervisorDetails.getStateId().equals(StateCode.AM.getStateCode())) { + + updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( + ashaId, approvalStatus, startDate, endDate, + approvalDate, ashaSupervisorUserId, + ashaSupervisorDetails.getUserName()); + + } else if(ashaSupervisorDetails.getStateId().equals(StateCode.CG.getStateCode())){ - return totalUpdated; + if ("ASHA Supervisor".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())) { + + updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( + ashaId, 104, startDate, endDate, + approvalDate, ashaSupervisorUserId, + ashaSupervisorDetails.getUserName()); + + } else { + + updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRangeForDefaultActivity( + ashaId, approvalStatus, startDate, endDate, + approvalDate, ashaSupervisorUserId, + ashaSupervisorDetails.getUserName()); + + } + } } - return incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( - ashaId, - approvalStatus, - startDate, - endDate, - approvalDate, - ashaSupervisorUserId, - ashaSupervisorUsername - ); + if (updatedCount > 0) { + sendApprovalNotification( + approvalStatus, + ashaId, + month, + year, + reason, + otherReason, + ashaSupervisorUserId, + ashaSupervisorDetails + ); + } + + return updatedCount; } catch (Exception e) { logger.error("Update claim :" + e.getMessage()); @@ -418,6 +665,72 @@ public int updateApprovalStatus(Integer ashaId, } } + + private void sendApprovalNotification( + Integer approvalStatus, + Integer ashaId, + Integer month, + Integer year, + String reason, + String otherReason, + Integer supervisorId, + UserServiceRoleDTO supervisor) { + + String title; + String body; + + if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { + + title = "Incentive Rejected"; + + body = "Incentive claim for " + Month.of(month).name() + " " + year + " has been rejected."; + + notificationService.sendNotification( + "FLW", "NA", + title, + body, + "INCENTIVE_REJECTED", + "INCENTIVE", + supervisorId); + + body = supervisor.getName() + " has rejected your incentive claim for " + + Month.of(month).name() + " " + year + "due to "+reason+" "+otherReason; + + notificationService.sendNotification( + "FLW", "NA", + title, + body, + "INCENTIVE_REJECTED", + "INCENTIVE", + ashaId); + + } else { + + title = "Incentive Approved"; + + body = "Incentive claim for " + Month.of(month).name() + " " + year + " has been approved."; + + notificationService.sendNotification( + "FLW", "NA", + title, + body, + "INCENTIVE_CLAIMED", + "INCENTIVE", + supervisorId); + + body = supervisor.getName() + " has approved your incentive claim for " + + Month.of(month).name() + " " + year; + + notificationService.sendNotification( + "FLW", "NA", + title, + body, + "INCENTIVE_CLAIMED", + "INCENTIVE", + ashaId); + } + } + private JSONObject buildEmptyIncentiveSummary() { JSONObject summary = new JSONObject(); summary.put("verified", 0); diff --git a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java index 7f1104d1d..c21cc9a5e 100644 --- a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java @@ -339,6 +339,7 @@ record = new IncentiveActivityRecord(); record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); record.setAshaId(userId); record.setBenId(0L); + record.setIsDefaultActivity(true); record.setAmount(Long.valueOf(activity.getRate())); record.setIsEligible(true); recordRepo.save(record); @@ -375,6 +376,7 @@ record = new IncentiveActivityRecord(); record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); record.setAshaId(userId); record.setBenId(0L); + record.setIsDefaultActivity(true); record.setAmount(Long.valueOf(activity.getRate())); record.setIsEligible(true); recordRepo.save(record); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 034fbcc4a..0b93c5177 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -71,4 +71,4 @@ spring.main.allow-bean-definition-overriding=true spring.redis.password= spring.redis.port=6379 -notificationurl=https://uatamrit.piramalswasthya.org/common-api/firebaseNotification/sendNotification +notificationurl=firebaseNotification/sendNotification From 0532e0a2c01adf09ce97a1677d6b9c792ceb0309 Mon Sep 17 00:00:00 2001 From: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Date: Fri, 31 Jul 2026 11:47:04 +0530 Subject: [PATCH 012/237] Fix/handel approval status of mt (#306) * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix anc incentive logic * fix 4th anc incentive issue * fix 4th anc incentive issue * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * changes logic for cg incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive * handel overdue incentive --- pom.xml | 2 +- .../flw/domain/iemr/IncentiveActivity.java | 5 - .../masterEnum/IncentiveApprovalStatus.java | 3 +- .../repo/iemr/AshaSupervisorLoginRepo.java | 64 ++++ .../flw/repo/iemr/IncentiveRecordRepo.java | 137 ++++++-- .../repo/iemr/SupervisorDashboardRepo.java | 39 ++- .../service/impl/ChildCareServiceImpl.java | 12 +- .../service/impl/DeathReportsServiceImpl.java | 68 ---- .../impl/DiseaseControlServiceImpl.java | 20 ++ .../service/impl/IncentiveServiceImpl.java | 47 ++- .../impl/MaternalHealthServiceImpl.java | 34 +- .../impl/SupervisorDashboardServiceImpl.java | 322 +++++++++++++++--- 12 files changed, 582 insertions(+), 171 deletions(-) diff --git a/pom.xml b/pom.xml index 576c0cdfb..b9c36ae84 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iemr.common.flw flw-api - 3.8.2 + 3.10.0 war FLW-API diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index a37f15017..a62d73b9f 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -65,9 +65,4 @@ public class IncentiveActivity { - - @Column(name = "state_activity_code") - private Integer stateActivityCode; - - } diff --git a/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java b/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java index e40ecc980..4149cab0f 100644 --- a/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java +++ b/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java @@ -5,7 +5,8 @@ public enum IncentiveApprovalStatus { VERIFIED(101, "Verified"), PENDING(102, "Pending"), REJECTED(103, "Rejected"), - OVERDUE(104, "Overdue"); + OVERDUE(104, "Overdue"), + APPROVED(105, "Approved"); private final int code; private final String label; diff --git a/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java index 78bb368bf..3b52abe28 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java @@ -55,6 +55,70 @@ List getAshasAtFacility( @Param("endDate") Timestamp endDate); + @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID " + + "AND u.Deleted = false " + + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + + "JOIN incentive_activity_record iar " + + "ON iar.asha_id = asm.ashaUserID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.facilityID = :facilityID " + + "AND asm.deleted = false " + + "AND iar.is_claimed = true " + + "AND iar.start_date >= :startDate " + + "AND iar.end_date < :endDate " + + "AND (" + + " :approvalStatus = 0 " + + " OR (:approvalStatus = 105 AND iar.approval_status IN (101,105)) " + + " OR (:approvalStatus = 106 AND iar.approval_status = 102) " + + " OR (:approvalStatus NOT IN (105,106) AND iar.approval_status = :approvalStatus)" + + ")", + nativeQuery = true) + List getAshasAtFacilityCg( + @Param("supervisorUserID") Integer supervisorUserID, + @Param("facilityID") Integer facilityID, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + + @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID " + + "AND u.Deleted = false " + + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + + "JOIN incentive_activity_record iar " + + "ON iar.asha_id = asm.ashaUserID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false " + + "AND (" + + " (:approvalStatus = 106 AND (iar.is_claimed = false OR iar.is_claimed IS NULL)) " + + " OR (:approvalStatus <> 106 AND iar.is_claimed = true)" + + ") " + + "AND iar.start_date >= :startDate " + + "AND iar.end_date < :endDate " + + "AND (" + + " :approvalStatus = 0 " + + " OR (:approvalStatus = 105 AND iar.approval_status IN (101,105)) " + + " OR (:approvalStatus = 106 AND iar.approval_status = 102) " + + " OR (:approvalStatus NOT IN (105,106) AND iar.approval_status = :approvalStatus)" + + ")", + nativeQuery = true) + List getAshasAtFacilityCg( + @Param("supervisorUserID") Integer supervisorUserID, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + + @Query(value = "SELECT DISTINCT asm.ashaUserID, " + "u.FirstName, " + "u.LastName, " diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 81dc1865f..fdda98477 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -72,7 +72,7 @@ IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId( "SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), " + "SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), " + "SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), " + - "SUM(CASE WHEN record.approvalStatus = 104 THEN 1 ELSE 0 END) " + + "SUM(CASE WHEN record.approvalStatus = 105 THEN 1 ELSE 0 END) " + "FROM IncentiveActivityRecord record " + "WHERE record.ashaId = :ashaId " + "AND record.isClaimed = true " + @@ -88,19 +88,54 @@ List getStatusCountByAshaId( "SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), " + "SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), " + "SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), " + - "SUM(CASE WHEN record.approvalStatus = 104 THEN 1 ELSE 0 END) " + + "SUM(CASE WHEN record.approvalStatus IN (102,105) THEN 1 ELSE 0 END) " + "FROM IncentiveActivityRecord record " + "WHERE record.ashaId = :ashaId " + "AND record.isClaimed = true " + - "AND record.isDefaultActivity = true " + "AND record.createdDate >= :startDate " + "AND record.createdDate < :endDate") + List getStatusCountByAshaIdANM( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + @Query(""" +SELECT + SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus IN (101,105) THEN 1 ELSE 0 END) +FROM IncentiveActivityRecord record +WHERE record.ashaId = :ashaId +AND record.isClaimed = true +AND record.isDefaultActivity = true +AND record.createdDate >= :startDate +AND record.createdDate < :endDate +""") List getStatusCountByAshaIdOfDefaultActivity( @Param("ashaId") Integer ashaId, @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate); + @Query(""" +SELECT + SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus IN (101,105) THEN 1 ELSE 0 END) +FROM IncentiveActivityRecord record +WHERE record.ashaId = :ashaId +AND record.isClaimed = false +AND record.createdDate >= :startDate +AND record.createdDate < :endDate +""") + List getStatusUnclaimedCountByAshaId( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + @Query("SELECT COALESCE(SUM(record.amount), 0) " + "FROM IncentiveActivityRecord record " + @@ -118,6 +153,66 @@ Long getTotalAmountByAsha( @Param("approvalStatus") Integer approvalStatus, @Param("stateCode") Integer stateCode); + + @Query(""" + SELECT COALESCE(SUM(record.amount), 0) + FROM IncentiveActivityRecord record + JOIN IncentiveActivity master ON record.activityId = master.id + WHERE record.ashaId = :ashaId + AND master.state = :stateCode + AND record.isClaimed = true + AND record.startDate >= :fromDate + AND record.endDate <= :toDate + AND ( + :approvalStatus = 0 + OR ( + :approvalStatus = 102 + AND record.approvalStatus IN (102, 105) + ) + OR ( + :approvalStatus <> 102 + AND record.approvalStatus = :approvalStatus + ) + ) +""") + Long getTotalAmountByAshaANM( + @Param("ashaId") Integer ashaId, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate, + @Param("approvalStatus") Integer approvalStatus, + @Param("stateCode") Integer stateCode + ); + + @Query(""" + SELECT COALESCE(SUM(record.amount), 0) + FROM IncentiveActivityRecord record + JOIN IncentiveActivity master ON record.activityId = master.id + WHERE record.ashaId = :ashaId + AND master.state = :stateCode + AND record.isClaimed = true + AND record.isDefaultActivity = false + AND record.startDate >= :fromDate + AND record.endDate <= :toDate + AND ( + :approvalStatus = 0 + OR ( + :approvalStatus = 102 + AND record.approvalStatus IN (102, 105) + ) + OR ( + :approvalStatus <> 102 + AND record.approvalStatus = :approvalStatus + ) + ) +""") + Long getTotalAmountByAshaANMbeforeClaimedHour( + @Param("ashaId") Integer ashaId, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate, + @Param("approvalStatus") Integer approvalStatus, + @Param("stateCode") Integer stateCode + ); + @Query("SELECT COALESCE(SUM(record.amount), 0) " + "FROM IncentiveActivityRecord record " + "JOIN IncentiveActivity master ON record.activityId = master.id " + @@ -127,7 +222,11 @@ Long getTotalAmountByAsha( "AND record.isDefaultActivity = true " + "AND record.startDate >= :fromDate " + "AND record.endDate <= :toDate " + - "AND (:approvalStatus = 0 OR record.approvalStatus = :approvalStatus)") + "AND (" + + " :approvalStatus = 0 " + + " OR (:approvalStatus = 101 AND record.approvalStatus IN (101,105)) " + + " OR (:approvalStatus <> 101 AND record.approvalStatus = :approvalStatus)" + + ")") Long getDefaultActivityTotalAmountByAsha( @Param("ashaId") Integer ashaId, @Param("fromDate") Timestamp fromDate, @@ -188,31 +287,11 @@ int updateApprovalStatusByAshaAndDateRange( UPDATE IncentiveActivityRecord iar SET iar.approvalStatus = :approvalStatus, - - iar.verifiedByUserId = - CASE - WHEN iar.isDefaultActivity = false - THEN :ashaSupervisorUserId - ELSE iar.verifiedByUserId - END, - - iar.verifiedByUserName = - CASE - WHEN iar.isDefaultActivity = false - THEN :ashaSupervisorUserName - ELSE iar.verifiedByUserName - END, - - iar.approvalDate = - CASE - WHEN iar.isDefaultActivity = false - THEN :approvalDate - ELSE iar.approvalDate - END, - + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.approvalDate = :approvalDate, iar.reason = NULL, iar.otherReason = NULL - WHERE iar.ashaId = :ashaId AND iar.isClaimed = true AND iar.createdDate >= :startDate @@ -238,9 +317,11 @@ int updateApprovalStatusByAshaAndDateRangeForDefaultActivity( + "iar.otherReason = :otherReason, " + "iar.approvalDate = :approvalDate, " + "iar.verifiedByUserName = :ashaSupervisorUserName " - + "WHERE iar.isClaimed = true") + + "WHERE iar.isClaimed = true " + + "AND iar.ashaId = :ashaId") int updateApprovalStatusById( @Param("status") Integer status, + @Param("ashaId") Integer ashaId, @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, @Param("ashaSupervisorUserName") String ashaSupervisorUserName, @Param("reason") String reason, diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java index d1a1f6611..071aeab0e 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -80,6 +80,19 @@ List getUnclaimedCountByAshaIds( @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate); + + @Query(value = "SELECT COUNT(*) " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id = :ashaId " + + "AND iar.created_date >= :startDate " + + "AND iar.created_date < :endDate " + + "AND (iar.is_claimed = false OR iar.is_claimed IS NULL)", + nativeQuery = true) + Long getUnclaimedCountByAshaId( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + // Get facility details with geo names @Query(value = "SELECT DISTINCT f.FacilityID, f.FacilityName, " + "COALESCE(s.StateName,'') AS stateName, " @@ -107,7 +120,8 @@ List getUnclaimedCountByAshaIds( + "COUNT(*) AS totalRecords, " + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " - + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending " + + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending, " + + "SUM(CASE WHEN iar.approval_status IN (101, 105) THEN 1 ELSE 0 END) AS approved " + "FROM incentive_activity_record iar " + "WHERE iar.asha_id IN (:ashaIds) " + "AND iar.created_date >= :startDate " @@ -120,11 +134,32 @@ List getIncentiveStatusByAshaIds( @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate); + + + @Query(value = "SELECT iar.asha_id, " + + "COUNT(*) AS totalRecords, " + + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " + + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " + + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending, " + + "SUM(CASE WHEN iar.approval_status IN (102,105) THEN 1 ELSE 0 END) AS approved " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN (:ashaIds) " + + "AND iar.created_date >= :startDate " + + "AND iar.is_claimed = true " + + "AND iar.created_date < :endDate " + + "GROUP BY iar.asha_id", + nativeQuery = true) + List getIncentiveStatusByAshaIdsForAnm( + @Param("ashaIds") List ashaIds, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + @Query(value = "SELECT iar.asha_id, " + "COUNT(*) AS totalRecords, " + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " - + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending " + + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending, " + + "SUM(CASE WHEN iar.approval_status IN (101, 105) THEN 1 ELSE 0 END) AS approved " + "FROM incentive_activity_record iar " + "WHERE iar.asha_id IN (:ashaIds) " + "AND iar.created_date >= :startDate " diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index e65e0f53e..8a840f052 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -709,7 +709,8 @@ public List saveAllIfa(List dtoList, Intege savedList.forEach(data -> { Timestamp visitTimestamp = Timestamp.valueOf(data.getIfaProvisionDate().atStartOfDay()); - if(data.getIfaBottleCount().equals("10.0")){ + + if(data!=null){ incentiveLogicService.incentiveForGiveingIFA( data.getBeneficiaryId(), visitTimestamp, @@ -774,8 +775,10 @@ private IfaDistributionDTO mapToDTO(IfaDistribution entity) { fields.setIfa_provision_date(entity.getIfaProvisionDate().format(FORMATTER)); } fields.setMcp_card_upload(entity.getMcpCardUpload()); - fields.setIfa_bottle_count(Double.valueOf(entity.getIfaBottleCount())); + if(entity.getIfaBottleCount()!=null){ + fields.setIfa_bottle_count(Double.valueOf(entity.getIfaBottleCount())); + } dto.setFields(fields); return dto; } @@ -803,7 +806,10 @@ private IfaDistribution mapToEntity(IfaDistributionDTO dto, Integer userId) { entity.setIfaProvisionDate(null); } } - entity.setIfaBottleCount(dto.getFields().getIfa_bottle_count().toString()); + if(dto.getFields().getIfa_bottle_count()!=null){ + entity.setIfaBottleCount(dto.getFields().getIfa_bottle_count().toString()); + + } entity.setMcpCardUpload(dto.getFields().getMcp_card_upload()); } diff --git a/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java index b7eee7dd0..cfc772142 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java @@ -81,37 +81,6 @@ public String registerCDR(List cdrDTOs) { } } - public String updateCDRUploadFiles(CdrDTO cdrDTOs, Long incentiveActivityId) { - try { - Optional cdrOptional = cdrRepo.findById(cdrDTOs.getId()); - CDR cdr = new CDR(); - if (cdrOptional.isPresent()) { - cdr = cdrOptional.get(); - if (cdrDTOs.getCdrImage() != null && !cdrDTOs.getCdrImage().isEmpty()) { - cdr.setCdrImage(cdrDTOs.getCdrImage()); - } - - if (cdrDTOs.getCdrImage2() != null && !cdrDTOs.getCdrImage2().isEmpty()) { - cdr.setCdrImage2(cdrDTOs.getCdrImage2()); - } - - if (cdrDTOs.getDeathCertImage1() != null && !cdrDTOs.getDeathCertImage1().isEmpty()) { - cdr.setDeathCertImage1(cdrDTOs.getDeathCertImage1()); - } - - if (cdrDTOs.getDeathCertImage2() != null && !cdrDTOs.getDeathCertImage2().isEmpty()) { - cdr.setDeathCertImage2(cdrDTOs.getDeathCertImage2()); - } - } - cdrRepo.save(cdr); - - pendindDocService.updateIncentive(incentiveActivityId); - - return "no of cdr details update: "; - } catch (Exception e) { - return "error while saving cdr details: " + e.getMessage(); - } - } @Override public String registerMDSR(List mdsrDTOs) { @@ -141,43 +110,6 @@ public String registerMDSR(List mdsrDTOs) { } } - public String updateMDSR(MdsrDTO mdsrDTO, Long incentiveActivityId) { - try { - - Optional mdsrOptional = mdsrRepo.findById(mdsrDTO.getId()); - MDSR mdsr = new MDSR(); - - if (mdsrOptional.isPresent()) { - - mdsr = mdsrOptional.get(); - - if (mdsrDTO.getMdsr1File() != null && !mdsrDTO.getMdsr1File().isEmpty()) { - mdsr.setMdsr1File(mdsrDTO.getMdsr1File()); - } - - if (mdsrDTO.getMdsr2File() != null && !mdsrDTO.getMdsr2File().isEmpty()) { - mdsr.setMdsr2File(mdsrDTO.getMdsr2File()); - } - - if (mdsrDTO.getMdsrDeathCertFile() != null && !mdsrDTO.getMdsrDeathCertFile().isEmpty()) { - mdsr.setMdsrDeathCertFile(mdsrDTO.getMdsrDeathCertFile()); - } - - } else { - return "MDSR record not found with id: " + mdsrDTO.getId(); - } - - mdsrRepo.save(mdsr); - - // incentive update - pendindDocService.updateIncentive(incentiveActivityId); - - return "MDSR updated successfully for id: " + mdsrDTO.getId(); - - } catch (Exception e) { - return "error while updating mdsr details: " + e.getMessage(); - } - } @Override public List getCdrRecords(GetBenRequestHandler dto) { diff --git a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java index 35746b2f8..64bc90cf1 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java @@ -1269,6 +1269,26 @@ private void checkAndAddIncentives(ScreeningMalaria diseaseScreening) { } } + if (diseaseScreening.getCaseStatus().equals("Suspected")) { + if (!diseaseScreening.getMalariaTestType().isEmpty()) { + if (stateId.equals(StateCode.AM.getStateCode())) { + if (incentiveActivityForCollectSlideAM != null) { + addIncentive(incentiveActivityForCollectSlideAM, diseaseScreening); + + } + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + if (incentiveActivityForCollectSlideCG != null) { + addIncentive(incentiveActivityForCollectSlideCG, diseaseScreening); + + } + } + + + } + + } } private void addIncentive(IncentiveActivity diseaseScreeningActivity, MosquitoNetEntity diseaseScreening) { diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 8f814af20..cfdaaae26 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -370,10 +370,27 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege records = records.stream() .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) .collect(Collectors.toList()); - }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) ){ - records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) - .collect(Collectors.toList()); + }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { + if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { + records = records.stream() + .filter(r -> + validActivityIds.contains(r.getActivityId()) && + ( + r.getApprovalStatus() == 101 + || r.getApprovalStatus() == 103 + || r.getApprovalStatus() == 105 + || r.getApprovalStatus() == 104 + || ( + r.getApprovalStatus() == 102 + && ( + isAfter24Hours(r.getCalimedDate()) + || Boolean.FALSE.equals(r.getIsDefaultActivity()) + ) + ) + ) + ) + .collect(Collectors.toList()); + } } }else { @@ -396,6 +413,12 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege IncentiveActivity activity = incentivesRepo.findById(activityId).orElse(null); + Integer approvalStatus = list.stream() + .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) + .map(IncentiveActivityRecord::getApprovalStatus) + .orElse(0); + + if (activity == null) continue; long total = list.stream() @@ -408,6 +431,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege map.put("activityDec", activity.getDescription()); map.put("groupName", activity.getGroup()); map.put("isDefault", activity.getIsDefaultActivity()); + map.put("approvalStatus", approvalStatus); map.put("claimCount", list.size()); map.put("totalAmount", total); map.put("amount", activity.getRate()); @@ -431,6 +455,21 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege return new Gson().toJson(result); } + private boolean isAfter24Hours(Timestamp claimedDate) { + if (claimedDate == null) { + return false; + } + + long now = System.currentTimeMillis(); + long diff = now - claimedDate.getTime(); + + logger.info("Now: {}", new Timestamp(now)); + logger.info("ClaimedDate: {}", claimedDate); + logger.info("Diff(ms): {}", diff); + logger.info("Diff(hours): {}", diff / (1000 * 60 * 60.0)); + + return diff >= 24L * 60 * 60 * 1000; + } @Override public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { try { diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 41849ee3c..83d261ee1 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -439,7 +439,8 @@ public String savePNCVisit(List pncVisitDTOs) { logger.info("PNC visit details saved"); return "no of pnc details saved: " + pncList.size(); } catch (Exception e) { - logger.info("Saving PNC visit details failed with error : " + e.getMessage()); + logger.error("Saving PNC visit details failed", e); + } return null; } @@ -591,7 +592,6 @@ private Boolean yesNoToBoolean(String value) { private void checkAndAddAntaraIncentive(PNCVisit ect) { Integer userId = userRepo.getUserIdByName(ect.getCreatedBy()); Integer stateId = userRepo.getUserRole(userId).get(0).getStateId(); - logger.info("ContraceptionMethod:" + ect.getContraceptionMethod()); // logic for assam if (stateId.equals(StateCode.AM.getStateCode())) { @@ -708,18 +708,20 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { } if (ect.getPncPeriod() == 1 || ect.getPncPeriod() == 3 || ect.getPncPeriod() == 7) { + if(ect.getContraceptionMethod()!=null){ + if ((ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)") + || ect.getContraceptionMethod().equals("MiniLap")) + && ect.getSterilisationDate() != null) { + IncentiveActivity ppsActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.ACTIVITY.getDisplayName()); + if (ppsActivityCH != null) { - if ((ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)") - || ect.getContraceptionMethod().equals("MiniLap")) - && ect.getSterilisationDate() != null) { - IncentiveActivity ppsActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.ACTIVITY.getDisplayName()); - if (ppsActivityCH != null) { + addIncenticeRecord(ect, userId, ppsActivityCH); - addIncenticeRecord(ect, userId, ppsActivityCH); + } + } + } - } - } } } @@ -850,7 +852,7 @@ private void checkAndAddIncentives(List ancList, Integer userId) { if (ancFullActivityCH != null && ancVisit.getAncVisit() != null && ancVisit.getAncVisit() == 4) { - recordAncRelatedIncentive(ancFullActivityCH, ancVisit); + recordFullAncIncentive(ancFullActivityCH, ancVisit); } @@ -872,12 +874,12 @@ private void recordAncRelatedIncentive(IncentiveActivity incentiveActivity, ANCV if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(incentiveActivity.getId()); - record.setCreatedDate(ancVisit.getCreatedDate()); + record.setCreatedDate(ancVisit.getAncDate()); record.setCreatedBy(ancVisit.getCreatedBy()); - record.setUpdatedDate(ancVisit.getCreatedDate()); + record.setUpdatedDate(ancVisit.getAncDate()); record.setUpdatedBy(ancVisit.getCreatedBy()); - record.setStartDate(ancVisit.getCreatedDate()); - record.setEndDate(ancVisit.getCreatedDate()); + record.setStartDate(ancVisit.getAncDate()); + record.setEndDate(ancVisit.getAncDate()); record.setBenId(ancVisit.getBenId()); record.setAshaId(userId); record.setAmount(Long.valueOf(incentiveActivity.getRate())); diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index bf164baaf..b90b9f73a 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1,5 +1,6 @@ package com.iemr.flw.service.impl; +import java.math.BigDecimal; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; @@ -7,6 +8,7 @@ import java.util.*; import java.util.stream.Collectors; +import com.google.gson.Gson; import com.iemr.flw.domain.iemr.IncentiveActivityRecord; import com.iemr.flw.dto.iemr.UserServiceRoleDTO; import com.iemr.flw.masterEnum.IncentiveApprovalStatus; @@ -57,6 +59,9 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In Integer stateId = userService.getUserDetail(supervisorUserID).getStateId(); String rollName = userService.getUserDetail(supervisorUserID).getRoleName(); + LocalDate today = LocalDate.now(); + + // 1. Supervisor user details List supervisorRows = dashboardRepo.getSupervisorUserDetails(supervisorUserID); if (supervisorRows != null && !supervisorRows.isEmpty()) { @@ -75,6 +80,14 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In logger.info("Fetching ASHA details for supervisorUserID: {}", supervisorUserID); + LocalDate dueDate = LocalDate.of(year, month, 1) + .plusMonths(1) + .withDayOfMonth(5); + + boolean isOverDue = + rollName.equalsIgnoreCase("ANM") + && today.isAfter(dueDate); + List ashaRows; @@ -167,7 +180,7 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In } // 5. Get incentive status per ASHA (verified, rejected, pending, totalAmount) - long overallVerified = 0, overallRejected = 0, overallPending = 0; + long overallVerified = 0, overallRejected = 0, overallPending = 0, overallOverDue =0; long overallUnclaimed = 0; try { @@ -209,26 +222,33 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In List statusRows = dashboardRepo.getDefaultIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); if (statusRows != null) { for (Object[] sRow : statusRows) { - long verified = ((Number) sRow[2]).longValue(); + long verified = ((Number) sRow[5]).longValue(); long rejected = ((Number) sRow[3]).longValue(); long pending = ((Number) sRow[4]).longValue(); + if (verified > 0) overallVerified += 1; if (rejected > 0) overallRejected += 1; if (pending > 0) overallPending += 1; } } }else if("ANM".equalsIgnoreCase(rollName)){ - List statusRows = dashboardRepo.getIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); + List statusRows = dashboardRepo.getIncentiveStatusByAshaIdsForAnm(ashaIDs, startDate, endDate); if (statusRows != null) { for (Object[] sRow : statusRows) { long verified = ((Number) sRow[2]).longValue(); long rejected = ((Number) sRow[3]).longValue(); - long pending = ((Number) sRow[4]).longValue(); + long pending = ((Number) sRow[5]).longValue(); if (verified > 0) overallVerified += 1; if (rejected > 0) overallRejected += 1; - if (pending > 0) overallPending += 1; + if (pending > 0) { + if (isOverDue) { + overallOverDue++; + } else { + overallPending++; + } + } } } } @@ -255,7 +275,7 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In overallSummary.put("verified", overallVerified); overallSummary.put("rejected", overallRejected); overallSummary.put("pending", overallPending); - overallSummary.put("overDue", 0); + overallSummary.put("overDue", overallOverDue); overallSummary.put("unclaimed", overallUnclaimed); result.put("incentiveSummary", overallSummary); @@ -315,7 +335,7 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In public Map getAshasAtFacility(Integer supervisorId, Integer facilityId, Integer month, Integer year, Integer approvalStatusID) { Integer supervisorstateCode = userService.getUserDetail(supervisorId).getStateId(); - List rows; + List rows = null; LocalDate today = LocalDate.now(); @@ -324,6 +344,15 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci LocalDate currentMonthStartDate = LocalDate.of(year, month, 1); LocalDate currentMonthendLocalDate = currentMonthStartDate.plusMonths(1); + LocalDate dueDate = LocalDate.of(year, month, 1) + .plusMonths(1) + .withDayOfMonth(5); + + boolean isOverDue = + roleName.equalsIgnoreCase("ANM") + && today.isAfter(dueDate); + + logger.info("Login user role:"+ roleName); boolean isCurrentMonth = @@ -345,6 +374,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { + logger.info("ANM:" + roleName); if (facilityId.equals(0)) { @@ -359,18 +389,36 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci } } else { + logger.info("Other:" + roleName); if (facilityId.equals(0)) { - rows = ashaSupervisorLoginRepo.getAshasAtFacility( - supervisorId, approvalStatusID, startDate, endDate); + if(supervisorstateCode.equals(StateCode.CG.getStateCode())){ + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + rows = ashaSupervisorLoginRepo.getAshasAtFacilityCg( + supervisorId, approvalStatusID, startDate, endDate); + } + }else if(supervisorstateCode.equals(StateCode.AM.getStateCode())){ + rows = ashaSupervisorLoginRepo.getAshasAtFacility( + supervisorId, approvalStatusID, startDate, endDate); + } } else { - rows = ashaSupervisorLoginRepo.getAshasAtFacility( - supervisorId, facilityId, approvalStatusID, startDate, endDate); + if(supervisorstateCode.equals(StateCode.CG.getStateCode())){ + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + rows = ashaSupervisorLoginRepo.getAshasAtFacilityCg( + supervisorId, facilityId, approvalStatusID, startDate, endDate); + } + }else if(supervisorstateCode.equals(StateCode.AM.getStateCode())){ + rows = ashaSupervisorLoginRepo.getAshasAtFacility( + supervisorId, facilityId, approvalStatusID, startDate, endDate); + } + + } } + logger.info("Other:" + rows); - long overallVerified = 0, overallRejected = 0, overallPending = 0 ,overallApproved =0; + long overallVerified = 0, overallRejected = 0, overallPending = 0 , overallUnclaimed=0 ,overallOverDue =0; String facilityName = ""; String facilityType = ""; @@ -392,13 +440,30 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if(supervisorstateCode.equals(StateCode.CG.getStateCode())){ if("ASHA Supervisor".equalsIgnoreCase(roleName)){ - countList = incentiveRecordRepo.getStatusCountByAshaIdOfDefaultActivity(ashaId, startDate, endDate); + if(approvalStatusID.equals(106)){ + countList = incentiveRecordRepo.getStatusUnclaimedCountByAshaId(ashaId, startDate, endDate); + + }else { + countList = incentiveRecordRepo.getStatusCountByAshaIdOfDefaultActivity(ashaId, startDate, endDate); + + } + + logger.info("countList = {}", Arrays.deepToString(countList.toArray())); + + }else if(("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) )){ logger.info("ASHA_ID = {}", ashaId); logger.info("Role = {}", roleName); - countList = incentiveRecordRepo.getStatusCountByAshaId(ashaId, startDate, endDate); + if(approvalStatusID.equals(106)){ + countList = incentiveRecordRepo.getStatusUnclaimedCountByAshaId(ashaId, startDate, endDate); + + }else { + countList = incentiveRecordRepo.getStatusCountByAshaIdANM(ashaId, startDate, endDate); + + } + logger.info("Count List = {}", countList); @@ -417,12 +482,26 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci ashaId, startDate, endDate, approvalStatusID, stateCode); }else if(stateCode.equals(StateCode.CG.getStateCode())){ if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + if(approvalStatusID.equals(105)){ + totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( + ashaId, startDate, endDate, 101, stateCode); + }else { + totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); + } - totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( - ashaId, startDate, endDate, approvalStatusID, stateCode); }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) ){ - totalAmount = incentiveRecordRepo.getTotalAmountByAsha( - ashaId, startDate, endDate, approvalStatusID, stateCode); + if(approvalStatusID.equals(102)){ + totalAmount = incentiveRecordRepo.getTotalAmountByAshaANM( + ashaId, startDate, endDate, approvalStatusID, stateCode); + }else if(approvalStatusID.equals(104)){ + totalAmount = incentiveRecordRepo.getTotalAmountByAshaANM( + ashaId, startDate, endDate, 105, stateCode); + } else { + totalAmount = incentiveRecordRepo.getTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); + } + } } @@ -445,21 +524,100 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci List dbRecords = incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate); if("ASHA Supervisor".equalsIgnoreCase(roleName)){ - incentiveActivityRecord = dbRecords.stream() - .filter(r -> approvalStatusID == 0 || - approvalStatusID.equals(r.getApprovalStatus()) && r.getIsDefaultActivity() && isWithin24Hours(r.getCalimedDate())) - .collect(Collectors.toList()); + if(approvalStatusID.equals(105)){ + incentiveActivityRecord = dbRecords.stream() + .filter(r -> (r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(105)) && r.getIsDefaultActivity()) + .collect(Collectors.toList()); + }else if(approvalStatusID.equals(106)){ + incentiveActivityRecord = dbRecords.stream() + .filter(r ->r.getApprovalStatus().equals(102) && r.getIsDefaultActivity() && !r.getIsClaimed()) + .collect(Collectors.toList()); + }else if(approvalStatusID.equals(0)){ + incentiveActivityRecord = dbRecords.stream() + .filter(r ->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed())|| r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104)) && r.getIsDefaultActivity()) + .collect(Collectors.toList()); + }else{ + incentiveActivityRecord = dbRecords.stream() + .filter(r ->( approvalStatusID == 0 || + approvalStatusID.equals(r.getApprovalStatus())) && r.getIsDefaultActivity() && isWithin24Hours(r.getCalimedDate())) + .collect(Collectors.toList()); + } + }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - incentiveActivityRecord = dbRecords.stream() - .filter(r -> approvalStatusID == 0 || - approvalStatusID.equals(r.getApprovalStatus()) && isAfter24Hours(r.getCreatedDate())) + + if (approvalStatusID.equals(102)) { + + incentiveActivityRecord = dbRecords.stream() + .peek(r -> { + if (r.getApprovalStatus().equals(102) + && Boolean.FALSE.equals(r.getIsDefaultActivity()) + && r.getCalimedDate() != null + && isAfter24Hours(r.getCalimedDate())) { + + r.setApprovalStatus(105); + } + }) + .filter(r -> + r.getApprovalStatus().equals(105) + || (r.getApprovalStatus().equals(102) + && Boolean.FALSE.equals(r.getIsDefaultActivity()))) + .collect(Collectors.toList()); + totalAmount = incentiveActivityRecord.stream() + .mapToLong(r -> r.getAmount()) + .sum(); + incentiveActivityRecord.forEach(r -> logger.info( + "activityId={}, status={}, isDefaultActivity={}", + r.getActivityId(), + r.getApprovalStatus(), + r.getIsDefaultActivity() + )); + + }else if (approvalStatusID.equals(104)) { + if(isOverDue){ + incentiveActivityRecord = dbRecords.stream() + .filter(r -> + r.getApprovalStatus().equals(105) + || (r.getApprovalStatus().equals(104))) + .peek(r -> { + if (r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(105)) { + r.setApprovalStatus(104); + } + }) + .collect(Collectors.toList()); + } + + }else if(approvalStatusID.equals(106)){ + incentiveActivityRecord = dbRecords.stream() + .filter(r->!r.getIsClaimed() && r.getApprovalStatus().equals(102)).collect(Collectors.toList()); + }else if(approvalStatusID.equals(0)){ + incentiveActivityRecord = dbRecords.stream() + .filter(r->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed()) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104))).collect(Collectors.toList()); + } else{ + incentiveActivityRecord = dbRecords.stream() + .filter(r -> { + + if (approvalStatusID != 0 + && !approvalStatusID.equals(r.getApprovalStatus())) { + return false; + } + + // 102 should be visible only after 24 hours + if (r.getApprovalStatus().equals(102)) { + return true; + } + + // 105 should always be visible + return true; + }) .peek(r -> { - if (isAfter24Hours(r.getCreatedDate()) - && r.getApprovalStatus().equals(102)) { - r.setApprovalStatus(104); + if (r.getApprovalStatus().equals(102) + && isAfter24Hours(r.getCalimedDate())) { + r.setApprovalStatus(105); } }) .collect(Collectors.toList()); + } + } @@ -467,6 +625,9 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci } logger.info("Final incentiveActivityRecord count: {}", incentiveActivityRecord.size()); + logger.info("Final incentiveActivityRecord: {}", + new Gson().toJson(incentiveActivityRecord)); + List> activityList = new ArrayList<>(); for (IncentiveActivityRecord record : incentiveActivityRecord) { Map activity = new HashMap<>(); @@ -495,37 +656,104 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci asha.put("facilityType", facilityType); asha.put("userId", row[0]); asha.put("fullName", fullName(row[1], row[2])); - asha.put("employeeId", str(row[3]).isEmpty() ? null : str(row[3])); + asha.put("employeeId", row[0]); asha.put("mobile", str(row[4]).isEmpty() ? null : str(row[4])); asha.put("gender", str(row[5]).isEmpty() ? null : str(row[5])); asha.put("totalAmount", totalAmount); asha.put("activities", activityList); - long pending = 0, verified = 0, rejected = 0 ,approved =0; + + + long pending = 0, verified = 0, rejected = 0 , unclaimedCount = 0 ; + + if (countList != null && !countList.isEmpty()) { Object[] counts = countList.get(0); - verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; - pending = counts[1] != null ? ((Number) counts[1]).longValue() : 0; - rejected = counts[2] != null ? ((Number) counts[2]).longValue() : 0; - approved = counts[3] != null ? ((Number) counts[3]).longValue() : 0; + logger.info("Count List = {}", Arrays.deepToString(countList.toArray())); + logger.info("101={}, 102={}, 103={}, 101+105={}", + counts[0], counts[1], counts[2], counts[3]); + + if(stateCode.equals(StateCode.CG.getStateCode())){ + if(roleName.equalsIgnoreCase("ANM")){ + verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; + rejected = counts[2] != null ? ((Number) counts[2]).longValue() : 0; + if(approvalStatusID.equals(106)){ + unclaimedCount = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + + }else if(approvalStatusID.equals(0)){ + unclaimedCount = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + pending = counts[3] != null ? ((Number) counts[3]).longValue() : 0; + + }else{ + + pending = counts[3] != null ? ((Number) counts[3]).longValue() : 0; + + } + + + }else if(roleName.equalsIgnoreCase("ASHA Supervisor")) { + if (approvalStatusID.equals(105)) { + // 101 + 105 + verified = counts[3] != null ? ((Number) counts[3]).longValue() : 0; + } else { + // only 101 + verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; + } + if(approvalStatusID.equals(106)){ + unclaimedCount = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + + }else if(approvalStatusID.equals(0)){ + unclaimedCount = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + pending = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + + }else{ + pending = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + + } + rejected = counts[2] != null ? ((Number) counts[2]).longValue() : 0; + + + } + }else { + verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; + pending = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + rejected = counts[2] != null ? ((Number) counts[2]).longValue() : 0; + } + } + + if (verified > 0) overallVerified += 1; if (rejected > 0) overallRejected += 1; - if (pending > 0) overallPending += 1; - if (approved > 0) overallApproved += 1; + if (pending > 0) { + if (isOverDue) { + overallOverDue++; + } else { + overallPending++; + } + } + + if (unclaimedCount > 0) overallUnclaimed += 1; asha.put("pending", pending); asha.put("verified", verified); asha.put("rejected", rejected); - asha.put("approved", approved); + asha.put("unClaimed", unclaimedCount); int approvalStatus = 0; if (!activityList.isEmpty()) { approvalStatus = (int) activityList.get(0).get("approvalStatus"); } - if (pending == 0 && verified == 0 && rejected == 0) continue; + if(!approvalStatusID.equals(106)){ + if (totalAmount == null || totalAmount <= 0) continue; + + } + + + if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0) continue; + if (approvalStatusID.equals(0)) { asha.put("approvalStatus", approvalStatus); @@ -543,7 +771,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci approvalStatus.put("verified", overallVerified); approvalStatus.put("pending", overallPending); approvalStatus.put("rejected", overallRejected); - approvalStatus.put("approved", overallApproved); + approvalStatus.put("unClaimed", overallUnclaimed); response.put("approvalStatus", approvalStatus); response.put("data", ashaList); @@ -557,8 +785,15 @@ private boolean isAfter24Hours(Timestamp claimedDate) { return false; } - long diff = System.currentTimeMillis() - claimedDate.getTime(); - return diff >= 24 * 60 * 60 * 1000L; + long now = System.currentTimeMillis(); + long diff = now - claimedDate.getTime(); + + logger.info("Now: {}", new Timestamp(now)); + logger.info("ClaimedDate: {}", claimedDate); + logger.info("Diff(ms): {}", diff); + logger.info("Diff(hours): {}", diff / (1000 * 60 * 60.0)); + + return diff >= 24L * 60 * 60 * 1000; } private boolean isWithin24Hours(Timestamp claimedDate) { if (claimedDate == null) { @@ -608,6 +843,7 @@ public int updateApprovalStatus(Integer ashaId, if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { updatedCount = incentiveRecordRepo.updateApprovalStatusById( approvalStatus, + ashaId, ashaSupervisorUserId, ashaSupervisorDetails.getUserName(), reason, @@ -628,11 +864,11 @@ public int updateApprovalStatus(Integer ashaId, if ("ASHA Supervisor".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())) { updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( - ashaId, 104, startDate, endDate, + ashaId, 105, startDate, endDate, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); - } else { + } else if("ANM".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())){ updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRangeForDefaultActivity( ashaId, approvalStatus, startDate, endDate, From 067decdbe2c997a434ea1af47b3436d74a1383f6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 31 Jul 2026 14:45:03 +0530 Subject: [PATCH 013/237] fix notification tag --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index cfdaaae26..337d1a8c5 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -649,7 +649,7 @@ public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boo data.put("year", String.valueOf(year)); data.put("approval_status", String.valueOf(102)); data.put("priority", "HIGH"); - title = "Incentive Approved"; + title = "Incentive Claimed"; From 74ec533456223147ae002a6d6689054219396035 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 31 Jul 2026 15:37:58 +0530 Subject: [PATCH 014/237] handel overdue incentive --- .../com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index f6769fbd8..3170deba0 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -151,7 +151,7 @@ public void checkAndAddJsyIncentive(List delOutList) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityAM); } - if (institutionalDeliveryActivityCH != null && placeOfDelivery.toLowerCase().equals("Government Hospital")) { + if (institutionalDeliveryActivityCH != null) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityCH); } } From 113ecb2c89ec9279614ead698f6a592b07f36bae Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 19 Aug 2026 15:35:06 +0530 Subject: [PATCH 015/237] add feature of get asha details by Subcenter --- .../AshaSupervisorIncentiveApproval.java | 2 +- .../flw/service/SupervisorDashboardService.java | 2 +- .../impl/SupervisorDashboardServiceImpl.java | 17 ++++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java index 3ba457a64..0ef8bb026 100644 --- a/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java +++ b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java @@ -76,7 +76,7 @@ public String getSupervisorDashboard(@RequestBody AshaByFacilityRequestDTO reque try { if(token!=null){ - String result = supervisorDashboardService.getSupervisorDashboard(jwtUtil.extractUserId(token),request.getMonth(),request.getYear()); + String result = supervisorDashboardService.getSupervisorDashboard(jwtUtil.extractUserId(token),request.getMonth(),request.getYear(),request.getFacilityId()); response.setResponse(result); } diff --git a/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java b/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java index bc580a26d..29fb34166 100644 --- a/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java +++ b/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java @@ -5,7 +5,7 @@ public interface SupervisorDashboardService { - String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year); + String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year,Integer facilityId); Map getAshasAtFacility(Integer supervisorId, Integer facilityId, Integer month, Integer year, Integer approvalStatusID); diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index b90b9f73a..6a7961fa6 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -54,7 +54,7 @@ public class SupervisorDashboardServiceImpl implements SupervisorDashboardServic private NotificationService notificationService; @Override - public String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year) { + public String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year,Integer facilityId) { JSONObject result = new JSONObject(); Integer stateId = userService.getUserDetail(supervisorUserID).getStateId(); String rollName = userService.getUserDetail(supervisorUserID).getRoleName(); @@ -92,12 +92,19 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In List ashaRows; if ("ANM".equalsIgnoreCase(rollName) || "CHO".equalsIgnoreCase(rollName)) { + if(facilityId.equals(0)){ + List facilityIDs = + facilityLoginRepo.getUserFacilityIDs(supervisorUserID); - List facilityIDs = - facilityLoginRepo.getUserFacilityIDs(supervisorUserID); + ashaRows = + facilityLoginRepo.getAshaListByFacilities(facilityIDs); + }else { + + + ashaRows = facilityLoginRepo.getAshaListByFacilities( + Collections.singletonList(facilityId)); + } - ashaRows = - facilityLoginRepo.getAshaListByFacilities(facilityIDs); } else { From e4f477b9866fce4b20f33d2a4b33a6ff97ec742b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 19 Aug 2026 18:07:21 +0530 Subject: [PATCH 016/237] add feature of get asha details by Subcenter --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 6a7961fa6..ccf31456c 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -107,9 +107,14 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In } else { + if(facilityId.equals(0)){ + ashaRows = + dashboardRepo.getAshasWithFacilityInfo(supervisorUserID); + }else { + ashaRows = facilityLoginRepo.getAshaListByFacilities( + Collections.singletonList(facilityId)); + } - ashaRows = - dashboardRepo.getAshasWithFacilityInfo(supervisorUserID); } From e66b453bdfa8ba2af57ecba110c988870e8619dc Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 20 Aug 2026 11:17:31 +0530 Subject: [PATCH 017/237] add feature of get asha details by Subcenter --- .../AshaSupervisorIncentiveApproval.java | 17 ++ .../service/SupervisorDashboardService.java | 1 + .../impl/SupervisorDashboardServiceImpl.java | 278 ++++++++++++++++++ 3 files changed, 296 insertions(+) diff --git a/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java index 0ef8bb026..3905d2e6f 100644 --- a/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java +++ b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java @@ -66,7 +66,24 @@ public ResponseEntity getAshaListByFacility( } + @Operation(summary = "Get comprehensive ASHA Supervisor dashboard with facilities, ASHAs, villages and incentive data") + @PostMapping("/getSubCenter") + public String getSupervisorSubCenter(@RequestBody AshaByFacilityRequestDTO request,@RequestHeader(value = "JwtToken") String token ) { + OutputResponse response = new OutputResponse(); + logger.info("dashboard request{}",request.getFacilityId()); + + try { + if(token!=null){ + String result = supervisorDashboardService.getSupervisorSubCenter(jwtUtil.extractUserId(token),request.getMonth(),request.getYear()); + response.setResponse(result); + } + } catch (Exception e) { + logger.error("getSupervisorDashboard failed: " + e.getMessage(), e); + response.setError(e); + } + return response.toString(); + } @Operation(summary = "Get comprehensive ASHA Supervisor dashboard with facilities, ASHAs, villages and incentive data") @PostMapping("/dashboard") diff --git a/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java b/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java index 29fb34166..d406bf628 100644 --- a/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java +++ b/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java @@ -6,6 +6,7 @@ public interface SupervisorDashboardService { String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year,Integer facilityId); + String getSupervisorSubCenter(Integer supervisorUserID, Integer month, Integer year); Map getAshasAtFacility(Integer supervisorId, Integer facilityId, Integer month, Integer year, Integer approvalStatusID); diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index ccf31456c..35e449564 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -343,6 +343,284 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In + @Override + public String getSupervisorSubCenter(Integer supervisorUserID, Integer month, Integer year) { + JSONObject result = new JSONObject(); + Integer stateId = userService.getUserDetail(supervisorUserID).getStateId(); + String rollName = userService.getUserDetail(supervisorUserID).getRoleName(); + + LocalDate today = LocalDate.now(); + + + // 1. Supervisor user details + List supervisorRows = dashboardRepo.getSupervisorUserDetails(supervisorUserID); + if (supervisorRows != null && !supervisorRows.isEmpty()) { + Object[] sRow = supervisorRows.get(0); + JSONObject supervisor = new JSONObject(); + supervisor.put("userId", sRow[0]); + supervisor.put("fullName", fullName(sRow[1], sRow[2])); + supervisor.put("employeeId", str(sRow[3]).isEmpty() ? JSONObject.NULL : str(sRow[3])); + supervisor.put("mobile", str(sRow[4]).isEmpty() ? JSONObject.NULL : str(sRow[4])); + supervisor.put("gender", str(sRow[5]).isEmpty() ? JSONObject.NULL : str(sRow[5])); + result.put("supervisor", supervisor); + } + logger.info("Supervisor id"+supervisorUserID); + + // 2. Get all ASHAs with facility info + logger.info("Fetching ASHA details for supervisorUserID: {}", supervisorUserID); + + + LocalDate dueDate = LocalDate.of(year, month, 1) + .plusMonths(1) + .withDayOfMonth(5); + + boolean isOverDue = + rollName.equalsIgnoreCase("ANM") + && today.isAfter(dueDate); + + + List ashaRows; + + if ("ANM".equalsIgnoreCase(rollName) || "CHO".equalsIgnoreCase(rollName)) { + List facilityIDs = + facilityLoginRepo.getUserFacilityIDs(supervisorUserID); + + ashaRows = + facilityLoginRepo.getAshaListByFacilities(facilityIDs); + + + } else { + ashaRows = + dashboardRepo.getAshasWithFacilityInfo(supervisorUserID); + + + } + + if (ashaRows == null || ashaRows.isEmpty()) { + logger.warn("No ASHA records found for supervisorUserID: {}", supervisorUserID); + + result.put("totalAshaCount", 0); + result.put("incentiveSummary", buildEmptyIncentiveSummary()); + result.put("facilities", new JSONArray()); + + logger.info("Returning empty dashboard response for supervisorUserID: {}", supervisorUserID); + + return result.toString(); + } + + + + // Collect distinct facility IDs and ASHA IDs + + logger.info("Processing {} ASHA records", ashaRows.size()); + + Set facilityIDSet = new HashSet<>(); + Set ashaIDSet = new HashSet<>(); + + for (Object[] row : ashaRows) { + + logger.info("Complete Row: {}", Arrays.toString(row)); + + for (int i = 0; i < row.length; i++) { + logger.info("row[{}] = {} ({})", + i, + row[i], + row[i] != null ? row[i].getClass().getName() : "null"); + } + + + if (row[4] != null) + facilityIDSet.add((Integer) row[4]); + + if (row[0] != null) + ashaIDSet.add((Integer) row[0]); + + } + + List facilityIDs = new ArrayList<>(facilityIDSet); + List ashaIDs = new ArrayList<>(ashaIDSet); + + logger.info("Facility IDs: {}", facilityIDs); + logger.info("ASHA IDs: {}", ashaIDs); + result.put("totalAshaCount", ashaIDs.size()); + + // 3. Location from first facility + List facilityRows = dashboardRepo.getFacilityDetails(facilityIDs); + if (facilityRows != null && !facilityRows.isEmpty()) { + Object[] fRow = facilityRows.get(0); + JSONObject location = new JSONObject(); + location.put("state", str(fRow[2])); + location.put("district", str(fRow[3])); + location.put("blockOrUlb", str(fRow[4])); + location.put("locationType", str(fRow[5])); + result.put("location", location); + } + + // 4. Build village map (facilityID -> villages) + Map> villageMap = new HashMap<>(); + List villageRows = dashboardRepo.getVillagesForFacilities(facilityIDs); + if (villageRows != null) { + for (Object[] vRow : villageRows) { + Integer facID = (Integer) vRow[0]; + JSONObject village = new JSONObject(); + village.put("villageId", vRow[1]); + village.put("villageName", str(vRow[2])); + villageMap.computeIfAbsent(facID, k -> new ArrayList<>()).add(village); + } + } + + // 5. Get incentive status per ASHA (verified, rejected, pending, totalAmount) + long overallVerified = 0, overallRejected = 0, overallPending = 0, overallOverDue =0; + long overallUnclaimed = 0; + + try { + logger.info("Month: {}", month); + logger.info("Year: {}", year); + + LocalDate startLocalDate = LocalDate.of(year, month, 1); + LocalDate endLocalDate = startLocalDate.plusMonths(1); + + logger.info("startLocalDate {}", startLocalDate); + logger.info("endLocalDate {}", endLocalDate); + + Timestamp startDate = Timestamp.valueOf(startLocalDate.atStartOfDay()); + Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + logger.info("Asha ID" + ashaIDs); + + if(stateId.equals(StateCode.AM.getStateCode())){ + List statusRows = dashboardRepo.getIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); + if (statusRows != null) { + for (Object[] sRow : statusRows) { + long verified = ((Number) sRow[2]).longValue(); + long rejected = ((Number) sRow[3]).longValue(); + long pending = ((Number) sRow[4]).longValue(); + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + } + } + List unclaimedRows = dashboardRepo.getUnclaimedCountByAshaIds(ashaIDs, startDate, endDate); + if (unclaimedRows != null) { + for (Object[] uRow : unclaimedRows) { + long count = ((Number) uRow[1]).longValue(); + if (count > 0) overallUnclaimed += 1; + } + } + }else if(stateId.equals(StateCode.CG.getStateCode())){ + if("ASHA Supervisor".equalsIgnoreCase(rollName)){ + List statusRows = dashboardRepo.getDefaultIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); + if (statusRows != null) { + for (Object[] sRow : statusRows) { + long verified = ((Number) sRow[5]).longValue(); + long rejected = ((Number) sRow[3]).longValue(); + long pending = ((Number) sRow[4]).longValue(); + + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + } + } + }else if("ANM".equalsIgnoreCase(rollName)){ + List statusRows = dashboardRepo.getIncentiveStatusByAshaIdsForAnm(ashaIDs, startDate, endDate); + if (statusRows != null) { + for (Object[] sRow : statusRows) { + long verified = ((Number) sRow[2]).longValue(); + long rejected = ((Number) sRow[3]).longValue(); + long pending = ((Number) sRow[5]).longValue(); + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) { + if (isOverDue) { + overallOverDue++; + } else { + overallPending++; + } + } + } + } + } + + List unclaimedRows = dashboardRepo.getUnclaimedCountByAshaIds(ashaIDs, startDate, endDate); + if (unclaimedRows != null) { + for (Object[] uRow : unclaimedRows) { + long count = ((Number) uRow[1]).longValue(); + if (count > 0) overallUnclaimed += 1; + } + } + } + + + } catch (Exception e) { + logger.error("Error fetching incentive status: " + e.getMessage(), e); + + } + + + + // Overall incentive summary across all ASHAs + JSONObject overallSummary = new JSONObject(); + overallSummary.put("verified", overallVerified); + overallSummary.put("rejected", overallRejected); + overallSummary.put("pending", overallPending); + overallSummary.put("overDue", overallOverDue); + overallSummary.put("unclaimed", overallUnclaimed); + result.put("incentiveSummary", overallSummary); + + // 7. Build facilities array with nested ASHAs + Map> ashasByFacility = new HashMap<>(); + for (Object[] row : ashaRows) { + Integer facID = (Integer) row[4]; + ashasByFacility.computeIfAbsent(facID, k -> new ArrayList<>()).add(row); + } + + Map facilityDetailsMap = new HashMap<>(); + if (facilityRows != null) { + for (Object[] fRow : facilityRows) { + facilityDetailsMap.put((Integer) fRow[0], fRow); + } + } + + JSONArray facilitiesArray = new JSONArray(); + for (Integer facID : facilityIDs) { + JSONObject facility = new JSONObject(); + facility.put("facilityId", facID); + + Object[] fDetails = facilityDetailsMap.get(facID); + if (fDetails != null) { + facility.put("facilityName", str(fDetails[1])); + facility.put("facilityType", str(fDetails[6])); + } + + + // ASHAs at this facility + JSONArray ashasArray = new JSONArray(); + List facAshaRows = ashasByFacility.get(facID); + if (facAshaRows != null) { + for (Object[] row : facAshaRows) { + Integer ashaId = (Integer) row[0]; + JSONObject asha = new JSONObject(); + asha.put("userId", ashaId); + asha.put("fullName", fullName(row[1], row[2])); + asha.put("employeeId", str(row[6]).isEmpty() ? JSONObject.NULL : str(row[6])); + asha.put("mobile", str(row[7]).isEmpty() ? JSONObject.NULL : str(row[7])); + + ashasArray.put(asha); + } + } + + facility.put("ashaCount", ashasArray.length()); + facilitiesArray.put(facility); + } + + result.put("facilities", facilitiesArray); + return result.toString(); + } + + + @Override public Map getAshasAtFacility(Integer supervisorId, Integer facilityId, Integer month, Integer year, Integer approvalStatusID) { From 7099bbb9d4a19d6ac23e31c4cdfd42e654de3fe5 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 20 Aug 2026 12:58:34 +0530 Subject: [PATCH 018/237] add group cat name --- src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java | 3 +++ .../java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java | 2 ++ src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java | 2 ++ .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 2 ++ 4 files changed, 9 insertions(+) diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index a62d73b9f..6402d9208 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -63,6 +63,9 @@ public class IncentiveActivity { @Column(name = "is_default_activity") private Boolean isDefaultActivity; + @Column(name = "group_category_name") + private String groupCategoryName; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java index b6d193e63..67cb9af3a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java @@ -87,4 +87,6 @@ public class IncentiveActivityRecord { @Transient private String groupName; + + @Transient String groupCategoryName; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java index 354e762d5..6f9cd63d2 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java @@ -47,6 +47,8 @@ public class IncentiveRecordDTO { private String groupName; + private String groupCategoryName; + private String reason; private String otherReason; diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 337d1a8c5..69d36f135 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -517,6 +517,7 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { incentivesRepo.findById(request.getActivityId()).orElse(null); String groupName = activity != null ? activity.getGroup() : ""; + String groupCategoryName = activity != null ? activity.getGroupCategoryName() : ""; String description = activity != null ? activity.getDescription() : ""; // 🔹 Map result @@ -532,6 +533,7 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { r.setGroupName(groupName); r.setActivityDec(description); + r.setGroupCategoryName(groupCategoryName); return modelMapper.map(r, IncentiveRecordDTO.class); From 8f92c4bcae806010103b6686c003ea9d0d10c74c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 20 Aug 2026 13:00:02 +0530 Subject: [PATCH 019/237] add group cat name --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 69d36f135..5ae29ed45 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -517,7 +517,7 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { incentivesRepo.findById(request.getActivityId()).orElse(null); String groupName = activity != null ? activity.getGroup() : ""; - String groupCategoryName = activity != null ? activity.getGroupCategoryName() : ""; + String groupCategoryName = activity != null ? activity.getGroupCategoryName() :activity.getGroup(); String description = activity != null ? activity.getDescription() : ""; // 🔹 Map result From 634fef0781f3a3ee97f3c72eeb36f2e83842e9b4 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 20 Aug 2026 13:01:36 +0530 Subject: [PATCH 020/237] add group cat name --- src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java index 0ebf4aac6..7aa856463 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java @@ -25,6 +25,7 @@ public class IncentiveActivityDTO implements Serializable { private String group; private String groupName; + private String groupCategoryName; private String fmrCode; From ae131c1307744037c19f8e1667ea62e644d3c1b4 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 12:00:26 +0530 Subject: [PATCH 021/237] add group cat name --- .../flw/repo/iemr/IncentiveRecordRepo.java | 23 +++++++++++++++++++ .../service/impl/IncentiveServiceImpl.java | 10 ++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index fdda98477..c52a560fc 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -329,6 +329,29 @@ int updateApprovalStatusById( @Param("otherReason") String otherReason ); + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.approvalStatus = :status, " + + "iar.verifiedByUserId = :ashaSupervisorUserId, " + + "iar.reason = :reason, " + + "iar.otherReason = :otherReason, " + + "iar.approvalDate = :approvalDate, " + + "iar.verifiedByUserName = :ashaSupervisorUserName " + + "WHERE iar.isClaimed = true " + + "AND iar.id = incentiveId " + + "AND iar.ashaId = :ashaId") + int updateApprovalStatusByIdAndIncentiveId( + @Param("status") Integer status, + @Param("ashaId") Integer ashaId, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName, + @Param("reason") String reason, + @Param("approvalDate") Timestamp approvalDate, + @Param("otherReason") String otherReason, + @Param("incentiveId") Integer incentiveId + ); + @Modifying @Transactional @Query("UPDATE IncentiveActivityRecord iar " diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 5ae29ed45..0c5ccb490 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -154,7 +154,13 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { dto.setName(mapping.getName()); if (isCG) { - dto.setGroupName(""); + if(inc.getGroupCategoryName()!=null || !inc.getGroupCategoryName().isEmpty()){ + dto.setGroupName(inc.getGroupCategoryName()); + + }else { + dto.setGroupName(inc.getGroup()); + + } } else if (isAM) { dto.setGroupName(mapping.getGroup()); } @@ -177,7 +183,7 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { } else { if (isCG) { - dto.setGroupName(""); + dto.setGroupName(inc.getGroupCategoryName()); } else { dto.setGroupName(inc.getGroup()); From 68caa17024e33a7e0449b1418a8f0442f05ea901 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 12:05:13 +0530 Subject: [PATCH 022/237] add group cat name --- src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index c52a560fc..1829063c2 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -339,7 +339,7 @@ int updateApprovalStatusById( + "iar.approvalDate = :approvalDate, " + "iar.verifiedByUserName = :ashaSupervisorUserName " + "WHERE iar.isClaimed = true " - + "AND iar.id = incentiveId " + + "AND iar.id = incentiveId, " + "AND iar.ashaId = :ashaId") int updateApprovalStatusByIdAndIncentiveId( @Param("status") Integer status, From 230400ef398ceda29ca7d8fc7ccc0d5612e15557 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 12:08:30 +0530 Subject: [PATCH 023/237] add group cat name --- .../flw/repo/iemr/IncentiveRecordRepo.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 1829063c2..d4560f502 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -329,28 +329,28 @@ int updateApprovalStatusById( @Param("otherReason") String otherReason ); - @Modifying - @Transactional - @Query("UPDATE IncentiveActivityRecord iar " - + "SET iar.approvalStatus = :status, " - + "iar.verifiedByUserId = :ashaSupervisorUserId, " - + "iar.reason = :reason, " - + "iar.otherReason = :otherReason, " - + "iar.approvalDate = :approvalDate, " - + "iar.verifiedByUserName = :ashaSupervisorUserName " - + "WHERE iar.isClaimed = true " - + "AND iar.id = incentiveId, " - + "AND iar.ashaId = :ashaId") - int updateApprovalStatusByIdAndIncentiveId( - @Param("status") Integer status, - @Param("ashaId") Integer ashaId, - @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, - @Param("ashaSupervisorUserName") String ashaSupervisorUserName, - @Param("reason") String reason, - @Param("approvalDate") Timestamp approvalDate, - @Param("otherReason") String otherReason, - @Param("incentiveId") Integer incentiveId - ); +// @Modifying +// @Transactional +// @Query("UPDATE IncentiveActivityRecord iar " +// + "SET iar.approvalStatus = :status, " +// + "iar.verifiedByUserId = :ashaSupervisorUserId, " +// + "iar.reason = :reason, " +// + "iar.otherReason = :otherReason, " +// + "iar.approvalDate = :approvalDate, " +// + "iar.verifiedByUserName = :ashaSupervisorUserName " +// + "WHERE iar.isClaimed = true " +// + "AND iar.id = incentiveId, " +// + "AND iar.ashaId = :ashaId") +// int updateApprovalStatusByIdAndIncentiveId( +// @Param("status") Integer status, +// @Param("ashaId") Integer ashaId, +// @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, +// @Param("ashaSupervisorUserName") String ashaSupervisorUserName, +// @Param("reason") String reason, +// @Param("approvalDate") Timestamp approvalDate, +// @Param("otherReason") String otherReason, +// @Param("incentiveId") Integer incentiveId +// ); @Modifying @Transactional From 95f509d0d11e5b9e4b46a213dd8ac07950816a25 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 12:18:00 +0530 Subject: [PATCH 024/237] add group cat name --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 0c5ccb490..fefd76fcd 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -183,7 +183,10 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { } else { if (isCG) { - dto.setGroupName(inc.getGroupCategoryName()); + if(inc.getGroupCategoryName()!=null || !inc.getGroupCategoryName().isEmpty()){ + dto.setGroupName(inc.getGroupCategoryName()); + + } } else { dto.setGroupName(inc.getGroup()); From 082b7c7a4d19eccb52fa3122281ff1c87ca89a5b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 12:29:30 +0530 Subject: [PATCH 025/237] add group cat name --- .../flw/service/impl/IncentiveServiceImpl.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index fefd76fcd..7459c759b 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -154,12 +154,11 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { dto.setName(mapping.getName()); if (isCG) { - if(inc.getGroupCategoryName()!=null || !inc.getGroupCategoryName().isEmpty()){ + if (inc.getGroupCategoryName() != null + && !inc.getGroupCategoryName().isEmpty()) { dto.setGroupName(inc.getGroupCategoryName()); - - }else { + } else { dto.setGroupName(inc.getGroup()); - } } else if (isAM) { dto.setGroupName(mapping.getGroup()); @@ -183,14 +182,14 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { } else { if (isCG) { - if(inc.getGroupCategoryName()!=null || !inc.getGroupCategoryName().isEmpty()){ + if (inc.getGroupCategoryName() != null + && !inc.getGroupCategoryName().isEmpty()) { dto.setGroupName(inc.getGroupCategoryName()); - + } else { + dto.setGroupName(inc.getGroup()); } - } else { dto.setGroupName(inc.getGroup()); - } } From 25b10ae3e7e87727ef56595bdb21df2172cfc56d Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 12:39:11 +0530 Subject: [PATCH 026/237] add group cat name --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 7459c759b..46c59d8b9 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -539,9 +539,8 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { } } - r.setGroupName(groupName); + r.setGroupName(groupCategoryName); r.setActivityDec(description); - r.setGroupCategoryName(groupCategoryName); return modelMapper.map(r, IncentiveRecordDTO.class); From bfb582c9b40f745a8e44925f50d39febb93c493b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 12:39:33 +0530 Subject: [PATCH 027/237] add group cat name --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 46c59d8b9..b2caeac0a 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -525,7 +525,7 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { incentivesRepo.findById(request.getActivityId()).orElse(null); String groupName = activity != null ? activity.getGroup() : ""; - String groupCategoryName = activity != null ? activity.getGroupCategoryName() :activity.getGroup(); +// String groupCategoryName = activity != null ? activity.getGroupCategoryName() :activity.getGroup(); String description = activity != null ? activity.getDescription() : ""; // 🔹 Map result @@ -539,8 +539,9 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { } } - r.setGroupName(groupCategoryName); + r.setGroupName(groupName); r.setActivityDec(description); +// r.setGroupCategoryName(groupCategoryName); return modelMapper.map(r, IncentiveRecordDTO.class); From 536bdf08406cf8d63571513450af4c315c3228ba Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 12:57:58 +0530 Subject: [PATCH 028/237] add group cat name --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index b2caeac0a..46c59d8b9 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -525,7 +525,7 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { incentivesRepo.findById(request.getActivityId()).orElse(null); String groupName = activity != null ? activity.getGroup() : ""; -// String groupCategoryName = activity != null ? activity.getGroupCategoryName() :activity.getGroup(); + String groupCategoryName = activity != null ? activity.getGroupCategoryName() :activity.getGroup(); String description = activity != null ? activity.getDescription() : ""; // 🔹 Map result @@ -539,9 +539,8 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { } } - r.setGroupName(groupName); + r.setGroupName(groupCategoryName); r.setActivityDec(description); -// r.setGroupCategoryName(groupCategoryName); return modelMapper.map(r, IncentiveRecordDTO.class); From 00d7c6a494b75e2bca22d6499b908cd60a879903 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 14:28:09 +0530 Subject: [PATCH 029/237] add group cat name --- .../com/iemr/flw/service/impl/IncentiveServiceImpl.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 46c59d8b9..d3f16fbba 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -437,7 +437,13 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege if(isCG){ map.put("activityId", activityId); map.put("activityDec", activity.getDescription()); - map.put("groupName", activity.getGroup()); + if(activity.getGroupCategoryName()!=null && !activity.getGroupCategoryName().isEmpty()){ + map.put("groupName", activity.getGroupCategoryName()); + + }else { + map.put("groupName", activity.getGroup()); + + } map.put("isDefault", activity.getIsDefaultActivity()); map.put("approvalStatus", approvalStatus); map.put("claimCount", list.size()); From 0f0f3a52a8ba4cc705bcb97c9f70021f32e85e1e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 15:21:38 +0530 Subject: [PATCH 030/237] add group cat name --- .../service/impl/MaternalHealthServiceImpl.java | 14 ++++++++++---- .../impl/SupervisorDashboardServiceImpl.java | 5 ++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 83d261ee1..361211327 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -660,18 +660,24 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { if (PPIUCDActivityCH != null) { - if (ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD)")) { - addIncenticeRecord(ect, userId, PPIUCDActivityCH); + if(ect.getContraceptionMethod()!=null){ + if (ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD)")) { + addIncenticeRecord(ect, userId, PPIUCDActivityCH); + } } + } if (femaleSterilizationActivityCH != null) { - if (ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { - addIncenticeRecord(ect, userId, femaleSterilizationActivityCH); + if(ect.getAnyContraceptionMethod()!=null){ + if (ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityCH); + } } + } diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 35e449564..aad33411f 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -108,8 +108,11 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In } else { if(facilityId.equals(0)){ + List facilityIDs = + facilityLoginRepo.getUserFacilityIDs(supervisorUserID); + ashaRows = - dashboardRepo.getAshasWithFacilityInfo(supervisorUserID); + facilityLoginRepo.getAshaListByFacilities(facilityIDs); }else { ashaRows = facilityLoginRepo.getAshaListByFacilities( Collections.singletonList(facilityId)); From 9f449433da12899489ba3b8108e34e8fc5148dfd Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 21 Aug 2026 16:55:39 +0530 Subject: [PATCH 031/237] add group cat name --- .../impl/SupervisorDashboardServiceImpl.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index aad33411f..c92c1ccf0 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -245,6 +245,25 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In if (verified > 0) overallVerified += 1; if (rejected > 0) overallRejected += 1; if (pending > 0) overallPending += 1; + + if (overallPending > 0) { + try { + String title = "Pending Incentive Claims"; + + String body = "You have " + overallPending + " pending incentive claim(s) for " + + Month.of(month).name() + " " + year + ". Please review them."; + + notificationService.sendNotification( + "FLW", "NA", + title, + body, + "INCENTIVE_PENDING", + "INCENTIVE", + supervisorUserID); + } catch (Exception ex) { + logger.error("Failed to send pending incentive notification for ashaId {}: {}", supervisorUserID, ex.getMessage(), ex); + } + } } } }else if("ANM".equalsIgnoreCase(rollName)){ @@ -264,6 +283,25 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In overallPending++; } } + + if (overallPending > 0) { + try { + String title = "Pending Incentive Claims"; + + String body = "You have " + overallPending + " pending incentive claim(s) for " + + Month.of(month).name() + " " + year + ". Please review them."; + + notificationService.sendNotification( + "FLW", "NA", + title, + body, + "INCENTIVE_PENDING", + "INCENTIVE", + supervisorUserID); + } catch (Exception ex) { + logger.error("Failed to send pending incentive notification for ashaId {}: {}", supervisorUserID, ex.getMessage(), ex); + } + } } } } From a341bdc231deb08b3d2e829a25b6c9f5558cec42 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 26 Aug 2026 12:30:46 +0530 Subject: [PATCH 032/237] implement single selection of incentive approval --- .../flw/repo/iemr/IncentiveRecordRepo.java | 88 ++++++++---- .../impl/SupervisorDashboardServiceImpl.java | 128 ++++++++++++++---- 2 files changed, 163 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index d4560f502..5e1a552d6 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -280,6 +280,26 @@ int updateApprovalStatusByAshaAndDateRange( @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, @Param("ashaSupervisorUserName") String ashaSupervisorUserName); + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.approvalStatus = :approvalStatus, " + + "iar.verifiedByUserId = :ashaSupervisorUserId, " + + "iar.reason = NULL, " + + "iar.otherReason = NULL, " + + "iar.approvalDate = :approvalDate, " + + "iar.verifiedByUserName = :ashaSupervisorUserName " + + "WHERE iar.id = :incentiveId " + + "AND iar.ashaId = :ashaId " + + "AND iar.isClaimed = true") + int updateApprovalStatusByIncentiveId( + @Param("incentiveId") Long incentiveId, + @Param("ashaId") Integer ashaId, + @Param("approvalStatus") Integer approvalStatus, + @Param("approvalDate") Timestamp approvalDate, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName); + @Modifying @Transactional @@ -307,7 +327,29 @@ int updateApprovalStatusByAshaAndDateRangeForDefaultActivity( @Param("ashaSupervisorUserName") String ashaSupervisorUserName ); - + @Modifying + @Transactional + @Query(""" +UPDATE IncentiveActivityRecord iar +SET + iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.approvalDate = :approvalDate, + iar.reason = NULL, + iar.otherReason = NULL +WHERE iar.id = :incentiveId +AND iar.ashaId = :ashaId +AND iar.isClaimed = true +""") + int updateApprovalStatusByIncentiveIdForDefaultActivity( + @Param("incentiveId") Long incentiveId, + @Param("ashaId") Integer ashaId, + @Param("approvalStatus") Integer approvalStatus, + @Param("approvalDate") Timestamp approvalDate, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName + ); @Modifying @Transactional @Query("UPDATE IncentiveActivityRecord iar " @@ -329,28 +371,28 @@ int updateApprovalStatusById( @Param("otherReason") String otherReason ); -// @Modifying -// @Transactional -// @Query("UPDATE IncentiveActivityRecord iar " -// + "SET iar.approvalStatus = :status, " -// + "iar.verifiedByUserId = :ashaSupervisorUserId, " -// + "iar.reason = :reason, " -// + "iar.otherReason = :otherReason, " -// + "iar.approvalDate = :approvalDate, " -// + "iar.verifiedByUserName = :ashaSupervisorUserName " -// + "WHERE iar.isClaimed = true " -// + "AND iar.id = incentiveId, " -// + "AND iar.ashaId = :ashaId") -// int updateApprovalStatusByIdAndIncentiveId( -// @Param("status") Integer status, -// @Param("ashaId") Integer ashaId, -// @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, -// @Param("ashaSupervisorUserName") String ashaSupervisorUserName, -// @Param("reason") String reason, -// @Param("approvalDate") Timestamp approvalDate, -// @Param("otherReason") String otherReason, -// @Param("incentiveId") Integer incentiveId -// ); + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.approvalStatus = :status, " + + "iar.verifiedByUserId = :ashaSupervisorUserId, " + + "iar.reason = :reason, " + + "iar.otherReason = :otherReason, " + + "iar.approvalDate = :approvalDate, " + + "iar.verifiedByUserName = :ashaSupervisorUserName " + + "WHERE iar.isClaimed = true " + + "AND iar.id = :incentiveId " + + "AND iar.ashaId = :ashaId") + int updateApprovalStatusByIdAndIncentiveId( + @Param("status") Integer status, + @Param("ashaId") Integer ashaId, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName, + @Param("reason") String reason, + @Param("approvalDate") Timestamp approvalDate, + @Param("otherReason") String otherReason, + @Param("incentiveId") Long incentiveId + ); @Modifying @Transactional diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index c92c1ccf0..a081ad542 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1170,45 +1170,113 @@ public int updateApprovalStatus(Integer ashaId, UserServiceRoleDTO ashaSupervisorDetails = userService.getUserDetail(ashaSupervisorUserId); int updatedCount = 0; + if(incentiveIds.isEmpty()){ + if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { + updatedCount = incentiveRecordRepo.updateApprovalStatusById( + approvalStatus, + ashaId, + ashaSupervisorUserId, + ashaSupervisorDetails.getUserName(), + reason, + approvalDate, + otherReason + ); + } else { + + if (ashaSupervisorDetails.getStateId().equals(StateCode.AM.getStateCode())) { + + updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( + ashaId, approvalStatus, startDate, endDate, + approvalDate, ashaSupervisorUserId, + ashaSupervisorDetails.getUserName()); + + } else if(ashaSupervisorDetails.getStateId().equals(StateCode.CG.getStateCode())){ + + if ("ASHA Supervisor".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())) { + + updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( + ashaId, 105, startDate, endDate, + approvalDate, ashaSupervisorUserId, + ashaSupervisorDetails.getUserName()); + + } else if("ANM".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())){ + + updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRangeForDefaultActivity( + ashaId, approvalStatus, startDate, endDate, + approvalDate, ashaSupervisorUserId, + ashaSupervisorDetails.getUserName()); - if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { - updatedCount = incentiveRecordRepo.updateApprovalStatusById( - approvalStatus, - ashaId, - ashaSupervisorUserId, - ashaSupervisorDetails.getUserName(), - reason, - approvalDate, - otherReason - ); - } else { + } + } + } + }else { + if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { + if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { + + for (String incentiveId : incentiveIds.split(",")) { + + Long id = Long.parseLong(incentiveId.trim()); + + updatedCount += incentiveRecordRepo.updateApprovalStatusByIdAndIncentiveId( + approvalStatus, + ashaId, + ashaSupervisorUserId, + ashaSupervisorDetails.getUserName(), + reason, + approvalDate, + otherReason, + id + ); + } + } + } else { - if (ashaSupervisorDetails.getStateId().equals(StateCode.AM.getStateCode())) { + if (ashaSupervisorDetails.getStateId().equals(StateCode.AM.getStateCode())) { + if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { - updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( - ashaId, approvalStatus, startDate, endDate, - approvalDate, ashaSupervisorUserId, - ashaSupervisorDetails.getUserName()); + for (String incentiveId : incentiveIds.split(",")) { - } else if(ashaSupervisorDetails.getStateId().equals(StateCode.CG.getStateCode())){ + Long id = Long.parseLong(incentiveId.trim()); - if ("ASHA Supervisor".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())) { + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveId(id, ashaId, approvalStatus, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); - updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( - ashaId, 105, startDate, endDate, - approvalDate, ashaSupervisorUserId, - ashaSupervisorDetails.getUserName()); + } + } - } else if("ANM".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())){ - updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRangeForDefaultActivity( - ashaId, approvalStatus, startDate, endDate, - approvalDate, ashaSupervisorUserId, - ashaSupervisorDetails.getUserName()); + } else if(ashaSupervisorDetails.getStateId().equals(StateCode.CG.getStateCode())){ + + if ("ASHA Supervisor".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())) { + if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { + + for (String incentiveId : incentiveIds.split(",")) { + + Long id = Long.parseLong(incentiveId.trim()); + + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveId(id, ashaId, 105, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); + + } + } + + + } else if("ANM".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())){ + if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { + + for (String incentiveId : incentiveIds.split(",")) { + Long id = Long.parseLong(incentiveId.trim()); + + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveIdForDefaultActivity(id, + ashaId, approvalStatus, + approvalDate, ashaSupervisorUserId, + ashaSupervisorDetails.getUserName()); + } + } + + } + } + } + } - } - } - } if (updatedCount > 0) { sendApprovalNotification( From 4417573127168fd3267ef9543786f1dabccdf0da Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 26 Aug 2026 15:49:41 +0530 Subject: [PATCH 033/237] optmize incentive api --- .../flw/repo/iemr/UserServiceRoleRepo.java | 6 + .../service/impl/IncentiveServiceImpl.java | 202 +++++++++++++++--- .../service/impl/TBSuspectedServiceImpl.java | 5 +- 3 files changed, 176 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java index 2b78b68f7..354088892 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java @@ -36,4 +36,10 @@ public interface UserServiceRoleRepo extends JpaRepository getUserRolesByIds(@Param("userIds") List userIds); + } diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index d3f16fbba..62c17d309 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -204,26 +204,25 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { } return null; } - @Override public String getAllIncentivesByUserId(GetBenRequestHandler request) { int page = 0; - int size = 20; + int size = 200; // bumped from 20 — fewer round trips for large histories Page pageResult; List finalDtos = new ArrayList<>(); - Integer stateCode = userService.getUserDetail(request.getAshaId()).getStateId(); - String userName = userService.getUserDetail(request.getAshaId()).getUserName(); - try { + // Fetch user detail ONCE instead of twice + UserServiceRoleDTO userDetail = userService.getUserDetail(request.getAshaId()); + Integer stateCode = userDetail.getStateId(); + String userName = userDetail.getUserName(); + try { if (stateCode.equals(StateCode.AM.getStateCode())) { checkMonthlyAshaIncentive(request.getAshaId()); } if (stateCode.equals(StateCode.CG.getStateCode())) { checkMonthlyAshaIncentiveForCg(request.getAshaId()); - } - } catch (Exception e) { logger.error("Error in checkMonthlyAshaIncentive: ", e); } @@ -231,7 +230,6 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { try { addIncentiveForIronTablets(request.getAshaId()); incentiveOfNcdReferal(request.getAshaId(), request.getVillageID()); - } catch (Exception e) { logger.error("Error in incentiveOfNcdReferal: ", e); } @@ -239,17 +237,9 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { boolean isCG = stateCode != null && stateCode.equals(StateCode.CG.getStateCode()); do { + Pageable pageable = PageRequest.of(page, size, Sort.by("id").descending()); - Pageable pageable = PageRequest.of( - page, - size, - Sort.by("id").descending() // latest first - ); - - pageResult = recordRepo.findRecordsByAsha( - request.getAshaId(), - pageable - ); + pageResult = recordRepo.findRecordsByAsha(request.getAshaId(), pageable); List entities = pageResult.getContent(); @@ -257,30 +247,27 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { return new Gson().toJson(Collections.emptyList()); } - // Step 2: Collect all activityIds — fetch valid ones in ONE query + // Bulk fetch valid activity ids List activityIds = entities.stream() .map(IncentiveActivityRecord::getActivityId) .distinct() .collect(Collectors.toList()); - // Single bulk query instead of N individual findIncentiveMasterById() calls Set validActivityIds = isCG ? incentivesRepo.findValidActivityIds(activityIds, true) : incentivesRepo.findValidActivityIds(activityIds, false); - // Filter entities based on valid activity IDs entities = entities.stream() .filter(e -> validActivityIds.contains(e.getActivityId())) .collect(Collectors.toList()); - // Step 3: Collect all benIds that need name lookup (name == null and benId > 0) + // Bulk fetch beneficiary names List benIdsToFetch = entities.stream() .filter(e -> e.getName() == null && e.getBenId() != null && e.getBenId() > 0) .map(IncentiveActivityRecord::getBenId) .distinct() .collect(Collectors.toList()); - // Step 4: Bulk fetch all beneficiary names in ONE query instead of 3 queries per record Map benIdToNameMap = new HashMap<>(); if (!benIdsToFetch.isEmpty()) { List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); @@ -292,7 +279,23 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { } } - // Step 5: Map entities to DTOs + // NEW: Bulk fetch verifier (supervisor) roles — replaces N+1 userRepo.getUserRole() calls + // Bulk fetch verifier (supervisor) roles — replaces N+1 userRepo.getUserRole() calls + List verifierIds = entities.stream() + .filter(e -> e.getName() == null && e.getVerifiedByUserId() != null) + .map(e -> e.getVerifiedByUserId().intValue()) // adjust if getVerifiedByUserId() already returns Integer + .distinct() + .collect(Collectors.toList()); + + Map verifierRoleMap = new HashMap<>(); + if (!verifierIds.isEmpty()) { + List roles = userRepo.getUserRolesByIds(verifierIds); + for (UserServiceRoleDTO r : roles) { + verifierRoleMap.put(r.getUserId(), r); + } + } + + // Map entities to DTOs List dtos = entities.stream().map(entry -> { if (entry.getName() == null) { if (entry.getBenId() != null && entry.getBenId() > 0) { @@ -304,40 +307,171 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { } else { entry.setName(""); } - if (entry.getVerifiedByUserId() != null) { - entry.setSupervisorRole(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getRoleName()); - entry.setVerifiedByUserName(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getName()); + if (entry.getVerifiedByUserId() != null) { + UserServiceRoleDTO role = verifierRoleMap.get(entry.getVerifiedByUserId()); + if (role != null) { + entry.setSupervisorRole(role.getRoleName()); + entry.setVerifiedByUserName(role.getName()); + } } + if (entry.getAshaId() != null) { if (entry.getCreatedBy() == null) { entry.setCreatedBy(userName); } - if (entry.getUpdatedBy() == null) { entry.setUpdatedBy(userName); } - if (entry.getIsEligible() == null) { entry.setIsEligible(true); } } - - } return modelMapper.map(entry, IncentiveRecordDTO.class); }).collect(Collectors.toList()); - finalDtos.addAll(dtos); + finalDtos.addAll(dtos); page++; } while (pageResult.hasNext()); - - Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); return gson.toJson(finalDtos); } +// @Override +// public String getAllIncentivesByUserId(GetBenRequestHandler request) { +// int page = 0; +// int size = 20; +// Page pageResult; +// List finalDtos = new ArrayList<>(); +// +// Integer stateCode = userService.getUserDetail(request.getAshaId()).getStateId(); +// String userName = userService.getUserDetail(request.getAshaId()).getUserName(); +// try { +// +// if (stateCode.equals(StateCode.AM.getStateCode())) { +// checkMonthlyAshaIncentive(request.getAshaId()); +// } +// if (stateCode.equals(StateCode.CG.getStateCode())) { +// checkMonthlyAshaIncentiveForCg(request.getAshaId()); +// +// } +// +// } catch (Exception e) { +// logger.error("Error in checkMonthlyAshaIncentive: ", e); +// } +// +// try { +// addIncentiveForIronTablets(request.getAshaId()); +// incentiveOfNcdReferal(request.getAshaId(), request.getVillageID()); +// +// } catch (Exception e) { +// logger.error("Error in incentiveOfNcdReferal: ", e); +// } +// +// boolean isCG = stateCode != null && stateCode.equals(StateCode.CG.getStateCode()); +// +// do { +// +// Pageable pageable = PageRequest.of( +// page, +// size, +// Sort.by("id").descending() // latest first +// ); +// +// pageResult = recordRepo.findRecordsByAsha( +// request.getAshaId(), +// pageable +// ); +// +// List entities = pageResult.getContent(); +// +// if (entities.isEmpty()) { +// return new Gson().toJson(Collections.emptyList()); +// } +// +// // Step 2: Collect all activityIds — fetch valid ones in ONE query +// List activityIds = entities.stream() +// .map(IncentiveActivityRecord::getActivityId) +// .distinct() +// .collect(Collectors.toList()); +// +// // Single bulk query instead of N individual findIncentiveMasterById() calls +// Set validActivityIds = isCG +// ? incentivesRepo.findValidActivityIds(activityIds, true) +// : incentivesRepo.findValidActivityIds(activityIds, false); +// +// // Filter entities based on valid activity IDs +// entities = entities.stream() +// .filter(e -> validActivityIds.contains(e.getActivityId())) +// .collect(Collectors.toList()); +// +// // Step 3: Collect all benIds that need name lookup (name == null and benId > 0) +// List benIdsToFetch = entities.stream() +// .filter(e -> e.getName() == null && e.getBenId() != null && e.getBenId() > 0) +// .map(IncentiveActivityRecord::getBenId) +// .distinct() +// .collect(Collectors.toList()); +// +// // Step 4: Bulk fetch all beneficiary names in ONE query instead of 3 queries per record +// Map benIdToNameMap = new HashMap<>(); +// if (!benIdsToFetch.isEmpty()) { +// List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); +// for (Object[] row : benDetails) { +// Long benId = ((Number) row[0]).longValue(); +// String first = row[1] != null ? (String) row[1] : ""; +// String last = row[2] != null ? (String) row[2] : ""; +// benIdToNameMap.put(benId, (first + " " + last).trim()); +// } +// } +// +// // Step 5: Map entities to DTOs +// List dtos = entities.stream().map(entry -> { +// if (entry.getName() == null) { +// if (entry.getBenId() != null && entry.getBenId() > 0) { +// String name = benIdToNameMap.getOrDefault(entry.getBenId(), ""); +// entry.setName(name); +// if (isCG) { +// entry.setIsEligible(true); +// } +// } else { +// entry.setName(""); +// } +// if (entry.getVerifiedByUserId() != null) { +// entry.setSupervisorRole(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getRoleName()); +// entry.setVerifiedByUserName(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getName()); +// +// } +// if (entry.getAshaId() != null) { +// if (entry.getCreatedBy() == null) { +// entry.setCreatedBy(userName); +// } +// +// if (entry.getUpdatedBy() == null) { +// entry.setUpdatedBy(userName); +// } +// +// if (entry.getIsEligible() == null) { +// entry.setIsEligible(true); +// } +// } +// +// +// } +// return modelMapper.map(entry, IncentiveRecordDTO.class); +// }).collect(Collectors.toList()); +// finalDtos.addAll(dtos); +// +// page++; +// +// } while (pageResult.hasNext()); +// +// +// +// Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); +// return gson.toJson(finalDtos); +// } // ================= GROUPED SUMMARY ================= @Override diff --git a/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java index 2a8c0eeb0..d2e43d7ca 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java @@ -54,10 +54,9 @@ public String save(TBSuspectedRequestDTO requestDTO) throws Exception { tbSuspected.setUserId(requestDTO.getUserId()); tbSuspectedRepo.save(tbSuspected); if(tbSuspected!=null){ - if(tbSuspected.getIsConfirmed()){ - incentiveLogicService.incentiveForTbSuspected(tbSuspected.getBenId(),tbSuspected.getVisitDate(),tbSuspected.getVisitDate(),tbSuspected.getUserId()); - } + incentiveLogicService.incentiveForTbSuspected(tbSuspected.getBenId(),tbSuspected.getVisitDate(),tbSuspected.getVisitDate(),tbSuspected.getUserId()); + } From c1da8d01f0c781e0ac2570075beea6c225bc9472 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 26 Aug 2026 16:34:30 +0530 Subject: [PATCH 034/237] optmize incentive api --- .../flw/repo/identity/BeneficiaryRepo.java | 7 +++ .../service/impl/ChildCareServiceImpl.java | 45 ++++++++++++++----- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java index e4ce22f04..516341181 100644 --- a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java +++ b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java @@ -117,4 +117,11 @@ Page getBenDataWithinDates( "FROM RMNCHBeneficiaryDetailsRmnch b " + "WHERE b.BenRegId IN :regIds AND b.benficieryid IS NOT NULL") List getBenIdsFromRegIDs(@Param("regIds") List regIds); + + // BeneficiaryRepo — replaces the per-row getBenIdFromRegID call + @Query("SELECT b.BenRegId, b.benficieryid " + + "FROM RMNCHBeneficiaryDetailsRmnch b " + + "WHERE b.BenRegId IN :regIds AND b.benficieryid IS NOT NULL") + List getBenIdsFromRegIds(@Param("regIds") List regIds); + } diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 8a840f052..8db662b54 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -375,24 +375,47 @@ public String saveHBNCDetails(List hbncRequestDTOs, Integer user public List getChildVaccinationDetails(GetBenRequestHandler dto) { try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); - List vaccinationDetails = childVaccinationRepo.getChildVaccinationDetails(user, dto.getFromDate(), dto.getToDate()); + List vaccinationDetails = + childVaccinationRepo.getChildVaccinationDetails(user, dto.getFromDate(), dto.getToDate()); - List result = new ArrayList<>(); - vaccinationDetails.forEach(childVaccination -> { - ChildVaccinationDTO vaccinationDTO = mapper.convertValue(childVaccination, ChildVaccinationDTO.class); - if(childVaccination.getBeneficiaryRegId()!=null){ - BigInteger benId = beneficiaryRepo.getBenIdFromRegID(childVaccination.getBeneficiaryRegId()); - vaccinationDTO.setBeneficiaryId(benId.longValue()); + if (vaccinationDetails.isEmpty()) { + return new ArrayList<>(); + } - } - if(!vaccinationDetails.isEmpty()){ - checkAndAddIncentives(vaccinationDetails); + // Bulk fetch all beneficiary IDs in ONE query instead of one-per-record + List regIds = vaccinationDetails.stream() + .map(ChildVaccination::getBeneficiaryRegId) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + Map regIdToBenIdMap = new HashMap<>(); + if (!regIds.isEmpty()) { + List benIdRows = beneficiaryRepo.getBenIdsFromRegIds(regIds); + for (Object[] row : benIdRows) { + Long regId = ((Number) row[0]).longValue(); + BigInteger benId = (BigInteger) row[1]; + regIdToBenIdMap.put(regId, benId); } + } + // Call ONCE for the whole batch — not per record + checkAndAddIncentives(vaccinationDetails); + + List result = new ArrayList<>(); + for (ChildVaccination childVaccination : vaccinationDetails) { + ChildVaccinationDTO vaccinationDTO = mapper.convertValue(childVaccination, ChildVaccinationDTO.class); + + if (childVaccination.getBeneficiaryRegId() != null) { + BigInteger benId = regIdToBenIdMap.get(childVaccination.getBeneficiaryRegId()); + if (benId != null) { + vaccinationDTO.setBeneficiaryId(benId.longValue()); + } + } result.add(vaccinationDTO); - }); + } + return result; } catch (Exception e) { logger.error(e.getMessage()); From d4437fbc3ba9fbb692b306ff473fc55f4524b9ba Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 27 Aug 2026 15:05:23 +0530 Subject: [PATCH 035/237] optmize incentive api --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index a081ad542..d6519c8d1 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1167,6 +1167,7 @@ public int updateApprovalStatus(Integer ashaId, Integer ashaSupervisorUserId = jwtUtil.extractUserId(token); logger.info("Asha Supervisor User Id : {}", ashaSupervisorUserId); + logger.info("Asha Incentive Id : {}", incentiveIds); UserServiceRoleDTO ashaSupervisorDetails = userService.getUserDetail(ashaSupervisorUserId); int updatedCount = 0; From cadcf489e8feeeaa5182355c2aa28613195110ae Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 27 Aug 2026 15:54:20 +0530 Subject: [PATCH 036/237] optmize incentive api --- .../com/iemr/flw/service/impl/IncentiveServiceImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 62c17d309..d0c7645f0 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -559,7 +559,10 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) .map(IncentiveActivityRecord::getApprovalStatus) .orElse(0); - + Long incentiveId = list.stream() + .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) + .map(IncentiveActivityRecord::getId) + .orElse(null); if (activity == null) continue; @@ -570,6 +573,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege Map map = new HashMap<>(); if(isCG){ map.put("activityId", activityId); + map.put("incentiveId",incentiveId); map.put("activityDec", activity.getDescription()); if(activity.getGroupCategoryName()!=null && !activity.getGroupCategoryName().isEmpty()){ map.put("groupName", activity.getGroupCategoryName()); @@ -586,6 +590,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege }else { map.put("activityId", activityId); + map.put("incentiveId",incentiveId); map.put("activityDec", activity.getDescription()); map.put("groupName", activity.getGroup()); map.put("claimCount", list.size()); From 935f4e945f714ce080f5989c8457830f346402a6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 27 Aug 2026 16:47:50 +0530 Subject: [PATCH 037/237] optmize incentive api --- .../com/iemr/flw/dto/identity/GetBenRequestHandler.java | 8 ++++++++ .../com/iemr/flw/service/impl/IncentiveServiceImpl.java | 1 + 2 files changed, 9 insertions(+) diff --git a/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java b/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java index d1a654ec6..37dc9761f 100644 --- a/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java +++ b/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java @@ -4,6 +4,7 @@ public class GetBenRequestHandler { private Integer villageID; + private Integer approvalStatus; private Timestamp fromDate; private Timestamp toDate; private Integer pageNo; @@ -98,4 +99,11 @@ public void setToDate(Timestamp toDate) { this.toDate = toDate; } + public Integer getApprovalStatus() { + return approvalStatus; + } + + public void setApprovalStatus(Integer approvalStatus) { + this.approvalStatus = approvalStatus; + } } diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index d0c7645f0..52b86cbcb 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -493,6 +493,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege && r.getEndDate() != null && r.getEndDate().toLocalDateTime().getMonthValue() == request.getMonth() && r.getEndDate().toLocalDateTime().getYear() == request.getYear() + && r.getApprovalStatus().equals(request.getApprovalStatus()) && r.getIsClaimed()) .toList(); From 14209d50fe7b980357421e7db9d55791b477c2c2 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 27 Aug 2026 16:55:52 +0530 Subject: [PATCH 038/237] optmize incentive api --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 52b86cbcb..6d48ab9e5 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -485,7 +485,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege Integer villageID = userRepo.getUserRole(request.getUserId()).get(0).getStateId(); boolean isCG = villageID != null && villageID.intValue() == StateCode.CG.getStateCode(); - + logger.info("Request getAllIncentivesGroupedSummary: "+request.getApprovalStatus()); List records = recordRepo.findRecordsByAsha(request.getUserId()) .stream() @@ -641,6 +641,7 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { && r.getActivityId().equals(request.getActivityId()) && r.getCreatedDate() != null && !r.getCreatedDate().before(startTs) + && r.getApprovalStatus().equals(request.getApprovalStatus()) && r.getCreatedDate().before(endTs)) .collect(Collectors.toList()); From 696d3e0ea2f178a7d0d3c0a0bc9c8600c0fd9fd8 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 27 Aug 2026 17:40:36 +0530 Subject: [PATCH 039/237] optmize incentive api --- .../flw/service/IncentiveLogicService.java | 2 + .../flw/service/impl/IncentiveLogicImpl.java | 42 ++++++++++++++ .../service/impl/IncentiveServiceImpl.java | 1 - .../impl/TBConfirmedCaseServiceImpl.java | 58 +++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/IncentiveLogicService.java b/src/main/java/com/iemr/flw/service/IncentiveLogicService.java index 8becce199..0c86ab7be 100644 --- a/src/main/java/com/iemr/flw/service/IncentiveLogicService.java +++ b/src/main/java/com/iemr/flw/service/IncentiveLogicService.java @@ -32,4 +32,6 @@ public interface IncentiveLogicService { IncentiveActivityRecord incentiveForGiveingIFA(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); IncentiveActivityRecord incentiveForTbSuspected(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForTbPreventiveFollowUp(Long benId, Timestamp completionDate, Timestamp completionDate1, Integer userId); } diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java index b6e4b7c7a..7200d4e04 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java @@ -85,6 +85,48 @@ public IncentiveActivityRecord incentiveForLeprosyPaucibacillaryConfirmed( } } + @Override + public IncentiveActivityRecord incentiveForTbPreventiveFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "TPT_PROVIDING"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check TB Incentive Exception: ", e); + return null; + } + } + @Override public IncentiveActivityRecord incentiveForTbSuspected(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { try { diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 6d48ab9e5..4fc18fdbd 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -641,7 +641,6 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { && r.getActivityId().equals(request.getActivityId()) && r.getCreatedDate() != null && !r.getCreatedDate().before(startTs) - && r.getApprovalStatus().equals(request.getApprovalStatus()) && r.getCreatedDate().before(endTs)) .collect(Collectors.toList()); 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 e89928def..3b030ae8a 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -113,6 +113,64 @@ private void checkIncentive(TBConfirmedCase entity){ } } + + + if (!Boolean.TRUE.equals(entity.getTreatmentCompleted()) + || entity.getActualTreatmentCompletionDate() == null + || entity.getTreatmentStartDate() == null) { + return; + } + + if (!hasMinimumFollowUpsCompleted(entity)) { + return; + } + + Timestamp completionDate = Timestamp.valueOf( + entity.getActualTreatmentCompletionDate().atStartOfDay() + ); + + incentiveLogicService.incentiveForTbPreventiveFollowUp( + entity.getBenId(), + completionDate, + completionDate, + entity.getUserId() + ); + } + + + private boolean hasMinimumFollowUpsCompleted(TBConfirmedCase entity) { + + String regimen = entity.getRegimenType(); + + int requiredMonths; + + switch (regimen) { + case "1HP": + requiredMonths = 1; + break; + + case "3HP": + case "3RH": + requiredMonths = 3; + break; + + case "6H": + case "6Lfx": + requiredMonths = 6; + break; + + case "4R": + requiredMonths = 4; + break; + + default: + return false; + } + + // TODO: + // actual monthly follow-up records count should be checked here + + return true; } @Override From 0aa0cf6ec35ce1048254f759843de868870ac6d0 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 31 Aug 2026 12:08:19 +0530 Subject: [PATCH 040/237] fix notification issue --- .../flw/repo/iemr/IncentiveRecordRepo.java | 1 - .../service/impl/IncentiveServiceImpl.java | 6 +-- .../impl/SupervisorDashboardServiceImpl.java | 42 +++++++++---------- .../flw/service/impl/UTPReronaPaymentJob.java | 21 +++++++--- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 5e1a552d6..b6b3b1dc0 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -219,7 +219,6 @@ Long getTotalAmountByAshaANMbeforeClaimedHour( "WHERE record.ashaId = :ashaId " + "AND master.state = :stateCode " + "AND record.isClaimed = true " + - "AND record.isDefaultActivity = true " + "AND record.startDate >= :fromDate " + "AND record.endDate <= :toDate " + "AND (" + diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 4fc18fdbd..a0ffe43c3 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -511,7 +511,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege if(isCG){ if("ASHA Supervisor".equalsIgnoreCase(roleName)){ records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) + .filter(r -> validActivityIds.contains(r.getActivityId())) .collect(Collectors.toList()); }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { @@ -525,10 +525,6 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege || r.getApprovalStatus() == 104 || ( r.getApprovalStatus() == 102 - && ( - isAfter24Hours(r.getCalimedDate()) - || Boolean.FALSE.equals(r.getIsDefaultActivity()) - ) ) ) ) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index d6519c8d1..c661b0ea7 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -253,13 +253,13 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In String body = "You have " + overallPending + " pending incentive claim(s) for " + Month.of(month).name() + " " + year + ". Please review them."; - notificationService.sendNotification( - "FLW", "NA", - title, - body, - "INCENTIVE_PENDING", - "INCENTIVE", - supervisorUserID); +// notificationService.sendNotification( +// "FLW", "NA", +// title, +// body, +// "INCENTIVE_PENDING", +// "INCENTIVE", +// supervisorUserID); } catch (Exception ex) { logger.error("Failed to send pending incentive notification for ashaId {}: {}", supervisorUserID, ex.getMessage(), ex); } @@ -291,13 +291,13 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In String body = "You have " + overallPending + " pending incentive claim(s) for " + Month.of(month).name() + " " + year + ". Please review them."; - notificationService.sendNotification( - "FLW", "NA", - title, - body, - "INCENTIVE_PENDING", - "INCENTIVE", - supervisorUserID); +// notificationService.sendNotification( +// "FLW", "NA", +// title, +// body, +// "INCENTIVE_PENDING", +// "INCENTIVE", +// supervisorUserID); } catch (Exception ex) { logger.error("Failed to send pending incentive notification for ashaId {}: {}", supervisorUserID, ex.getMessage(), ex); } @@ -775,8 +775,10 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci countList = incentiveRecordRepo.getStatusUnclaimedCountByAshaId(ashaId, startDate, endDate); }else { - countList = incentiveRecordRepo.getStatusCountByAshaIdOfDefaultActivity(ashaId, startDate, endDate); + countList = incentiveRecordRepo + .getStatusCountByAshaId( + ashaId, startDate, endDate); } logger.info("countList = {}", Arrays.deepToString(countList.toArray())); @@ -857,15 +859,15 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if("ASHA Supervisor".equalsIgnoreCase(roleName)){ if(approvalStatusID.equals(105)){ incentiveActivityRecord = dbRecords.stream() - .filter(r -> (r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(105)) && r.getIsDefaultActivity()) + .filter(r -> (r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(105))) .collect(Collectors.toList()); }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() - .filter(r ->r.getApprovalStatus().equals(102) && r.getIsDefaultActivity() && !r.getIsClaimed()) + .filter(r ->r.getApprovalStatus().equals(102) && !r.getIsClaimed()) .collect(Collectors.toList()); }else if(approvalStatusID.equals(0)){ incentiveActivityRecord = dbRecords.stream() - .filter(r ->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed())|| r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104)) && r.getIsDefaultActivity()) + .filter(r ->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed())|| r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104))) .collect(Collectors.toList()); }else{ incentiveActivityRecord = dbRecords.stream() @@ -881,7 +883,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveActivityRecord = dbRecords.stream() .peek(r -> { if (r.getApprovalStatus().equals(102) - && Boolean.FALSE.equals(r.getIsDefaultActivity()) && r.getCalimedDate() != null && isAfter24Hours(r.getCalimedDate())) { @@ -890,8 +891,7 @@ && isAfter24Hours(r.getCalimedDate())) { }) .filter(r -> r.getApprovalStatus().equals(105) - || (r.getApprovalStatus().equals(102) - && Boolean.FALSE.equals(r.getIsDefaultActivity()))) + || (r.getApprovalStatus().equals(102))) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() .mapToLong(r -> r.getAmount()) diff --git a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java index c45f18e1c..649db7ff8 100644 --- a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java +++ b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java @@ -11,6 +11,8 @@ import com.iemr.flw.repo.iemr.IncentivesRepo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -23,7 +25,7 @@ @Slf4j @Component -public class UTPReronaPaymentJob { +public class UTPReronaPaymentJob implements CommandLineRunner { @Autowired private IncentiveRecordRepo recordRepo; @@ -34,18 +36,23 @@ public class UTPReronaPaymentJob { @Autowired private UtpreronaPaymentIntegrationImpl paymentService; - // Runs automatically on 1st of every month at midnight - @Scheduled(cron = "0 0 0 1 * *") - public void sendMonthlyPayments() { +// // Runs automatically on 1st of every month at midnight +// @Scheduled(cron = "0 0 0 1 * *") +// public void sendMonthlyPayments() { +// triggerPayment(); +// } + + @Override + public void run(String... args) { + log.info("Running UTP Rerona Payment Job on startup..."); triggerPayment(); } - // ✅ Separate method — call this for immediate testing public void triggerPayment() { LocalDate today = LocalDate.now(); -// ✅ Current month ka data — testing ke liye +// ✅ Current month ka data LocalDate firstDay = today.withDayOfMonth(1); // Mar 1, 2026 LocalDate lastDay = today; // Mar 11, 2026 (aaj) @@ -192,4 +199,6 @@ public void triggerPayment() { log.info("Job Complete | Success: {} | Failed: {} | Skipped: {}", success, failed, skipped); log.info("========================================"); } + + } \ No newline at end of file From e5f7283815b5003f0b1c57c6ee4d871e58340d9e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 31 Aug 2026 15:10:23 +0530 Subject: [PATCH 041/237] fix notification issue --- .../com/iemr/flw/dto/PaymentResponse.java | 15 ++++ .../service/impl/IncentiveServiceImpl.java | 11 +-- .../impl/SupervisorDashboardServiceImpl.java | 6 +- .../flw/service/impl/UTPReronaPaymentJob.java | 51 +++++++++++- .../impl/UtpreronaPaymentIntegrationImpl.java | 79 ++++++++++++++----- 5 files changed, 128 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/iemr/flw/dto/PaymentResponse.java diff --git a/src/main/java/com/iemr/flw/dto/PaymentResponse.java b/src/main/java/com/iemr/flw/dto/PaymentResponse.java new file mode 100644 index 000000000..c9fcd2b0e --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/PaymentResponse.java @@ -0,0 +1,15 @@ +package com.iemr.flw.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class PaymentResponse { + + @JsonProperty("submission_id") + private String submissionId; + + private String status; + + private String receipt; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index a0ffe43c3..0c3deb78e 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -517,16 +517,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { records = records.stream() .filter(r -> - validActivityIds.contains(r.getActivityId()) && - ( - r.getApprovalStatus() == 101 - || r.getApprovalStatus() == 103 - || r.getApprovalStatus() == 105 - || r.getApprovalStatus() == 104 - || ( - r.getApprovalStatus() == 102 - ) - ) + validActivityIds.contains(r.getActivityId()) ) .collect(Collectors.toList()); } diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index c661b0ea7..b6ddc58b8 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -886,11 +886,11 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci && r.getCalimedDate() != null && isAfter24Hours(r.getCalimedDate())) { - r.setApprovalStatus(105); + r.setApprovalStatus(102); } }) .filter(r -> - r.getApprovalStatus().equals(105) + r.getApprovalStatus().equals(102) || (r.getApprovalStatus().equals(102))) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() @@ -907,7 +907,7 @@ && isAfter24Hours(r.getCalimedDate())) { if(isOverDue){ incentiveActivityRecord = dbRecords.stream() .filter(r -> - r.getApprovalStatus().equals(105) + r.getApprovalStatus().equals(102) || (r.getApprovalStatus().equals(104))) .peek(r -> { if (r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(105)) { diff --git a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java index 649db7ff8..a8d57b653 100644 --- a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java +++ b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java @@ -45,9 +45,58 @@ public class UTPReronaPaymentJob implements CommandLineRunner { @Override public void run(String... args) { log.info("Running UTP Rerona Payment Job on startup..."); - triggerPayment(); + triggerStaticPayment(); } // ✅ Separate method — call this for immediate testing + + public void triggerStaticPayment() { + try { + + Period period = new Period(); + period.setStart("2026-01-01"); + period.setEnd("2026-01-31"); + + VerifiedBy verifiedBy = new VerifiedBy(); + verifiedBy.setEmployeeId("34455"); + verifiedBy.setName("ASHA Supervisor/CHO name"); + + List items = new ArrayList<>(); + + PaymentItem item1 = new PaymentItem(); + item1.setActivityCode("1"); + item1.setCount("3"); + item1.setIncentiveAmount("300"); + items.add(item1); + + PaymentItem item2 = new PaymentItem(); + item2.setActivityCode("2"); + item2.setCount("4"); + item2.setIncentiveAmount("400"); + items.add(item2); + + PaymentRequest paymentRequest = new PaymentRequest( + "4d0d8f3a-0bh9b-fff4e7edd-8bdd7a-rfgggdjhdd", + "AMRIT", + period, + "4566", + "2026-02-01T02:00:00+05:30", + verifiedBy, + items + ); + + log.info("========================================"); + log.info("STATIC PAYMENT REQUEST"); + log.info("Payload: {}", new Gson().toJson(paymentRequest)); + log.info("========================================"); + + paymentService.sendPaymentRequest(paymentRequest); + + log.info("Static payment request sent successfully."); + + } catch (Exception e) { + log.error("Static payment request failed: {}", e.getMessage(), e); + } + } public void triggerPayment() { LocalDate today = LocalDate.now(); diff --git a/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java b/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java index f0e5a5544..e277cc318 100644 --- a/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java @@ -1,9 +1,8 @@ package com.iemr.flw.service.impl; import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.dto.PaymentResponse; import com.iemr.flw.dto.iemr.PaymentRequest; -import io.swagger.v3.oas.models.responses.ApiResponse; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.IOException; @@ -15,9 +14,13 @@ @Service public class UtpreronaPaymentIntegrationImpl { -// @Value("${ssdPortalUrl}") - private String API_URL = "https://nhmssd.assam.gov.in/APPMS_2024_25/api/utpreronaPayment.php"; - private String API_KEY = "41202fa384eab2725a17bbac58cf708bf04cd1dd5175010941606156dc36d6b5"; + + private String API_URL = + "https://nhmssd.assam.gov.in/APPMS_2024_25/api/utpreronaPayment.php"; + + private String API_KEY = + "YOUR_API_KEY"; + private static final int TIMEOUT_SECONDS = 30; private final HttpClient httpClient; @@ -27,16 +30,21 @@ public UtpreronaPaymentIntegrationImpl() { this.httpClient = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(TIMEOUT_SECONDS)) .build(); + this.objectMapper = new ObjectMapper(); } - public ApiResponse sendPaymentRequest(PaymentRequest paymentRequest) + public PaymentResponse sendPaymentRequest(PaymentRequest paymentRequest) throws IOException, InterruptedException { - String jsonBody = objectMapper.writeValueAsString(paymentRequest); + String jsonBody = + objectMapper.writeValueAsString(paymentRequest); + System.out.println("Sending Request:"); - System.out.println(objectMapper.writerWithDefaultPrettyPrinter() - .writeValueAsString(paymentRequest)); + System.out.println( + objectMapper.writerWithDefaultPrettyPrinter() + .writeValueAsString(paymentRequest) + ); HttpRequest httpRequest = HttpRequest.newBuilder() .uri(URI.create(API_URL)) @@ -47,20 +55,51 @@ public ApiResponse sendPaymentRequest(PaymentRequest paymentRequest) .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) .build(); - HttpResponse httpResponse = httpClient.send( - httpRequest, - HttpResponse.BodyHandlers.ofString() + HttpResponse httpResponse = + httpClient.send( + httpRequest, + HttpResponse.BodyHandlers.ofString() + ); + + System.out.println( + "Response Status: " + httpResponse.statusCode() + ); + + System.out.println( + "Response Body: " + httpResponse.body() ); - System.out.println("Response Status: " + httpResponse.statusCode()); - System.out.println("Response Body: " + httpResponse.body()); + if (httpResponse.statusCode() >= 200 + && httpResponse.statusCode() < 300) { + + PaymentResponse response = + objectMapper.readValue( + httpResponse.body(), + PaymentResponse.class + ); + + System.out.println( + "Submission ID: " + response.getSubmissionId() + ); + + System.out.println( + "Status: " + response.getStatus() + ); + + System.out.println( + "Receipt: " + response.getReceipt() + ); + + return response; - if (httpResponse.statusCode() == 200) { - return objectMapper.readValue(httpResponse.body(), ApiResponse.class); } else { - throw new IOException("API Error - Status: " + httpResponse.statusCode() - + " | Body: " + httpResponse.body()); + + throw new IOException( + "API Error - Status: " + + httpResponse.statusCode() + + " | Body: " + + httpResponse.body() + ); } } - -} +} \ No newline at end of file From d72a241d3ff579e30499a1bed2c0789e81637f1e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 31 Aug 2026 15:42:35 +0530 Subject: [PATCH 042/237] fix notification issue --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index b6ddc58b8..c661b0ea7 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -886,11 +886,11 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci && r.getCalimedDate() != null && isAfter24Hours(r.getCalimedDate())) { - r.setApprovalStatus(102); + r.setApprovalStatus(105); } }) .filter(r -> - r.getApprovalStatus().equals(102) + r.getApprovalStatus().equals(105) || (r.getApprovalStatus().equals(102))) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() @@ -907,7 +907,7 @@ && isAfter24Hours(r.getCalimedDate())) { if(isOverDue){ incentiveActivityRecord = dbRecords.stream() .filter(r -> - r.getApprovalStatus().equals(102) + r.getApprovalStatus().equals(105) || (r.getApprovalStatus().equals(104))) .peek(r -> { if (r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(105)) { From 7f4673063e0f2178ffb1904367a5788c3e6bb39a Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 31 Aug 2026 17:05:15 +0530 Subject: [PATCH 043/237] fix notification issue --- .../flw/controller/IncentiveController.java | 2 +- .../iemr/UpdateClaimedStatusRequestDTO.java | 1 + .../flw/repo/iemr/IncentiveRecordRepo.java | 14 ++++ .../iemr/flw/service/IncentiveService.java | 2 +- .../service/impl/IncentiveServiceImpl.java | 75 +++++++++++++------ 5 files changed, 70 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/IncentiveController.java b/src/main/java/com/iemr/flw/controller/IncentiveController.java index 5feead211..32a5c16fa 100644 --- a/src/main/java/com/iemr/flw/controller/IncentiveController.java +++ b/src/main/java/com/iemr/flw/controller/IncentiveController.java @@ -200,7 +200,7 @@ public ResponseEntity updateApprovalStatus( request.getMonth(), request.getYear(), request.isClaimed(), - token + token,request.getIncentiveId() ); Map response = new HashMap<>(); diff --git a/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java index 052b7d12f..556031b64 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java @@ -8,4 +8,5 @@ public class UpdateClaimedStatusRequestDTO { private Integer month; private Integer year; private boolean isClaimed; + private String incentiveId; } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index b6b3b1dc0..fac16c221 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -451,4 +451,18 @@ List getRecordsBySuperVisor( @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate, @Param("approvalStatus") Integer approvalStatus); + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.isClaimed = :isClaimed, " + + "iar.calimedDate = :calimedDate, " + + "iar.approvalStatus = 102 " + + "WHERE iar.ashaId = :ashaId " + + "AND iar.id = :incentiveId ") + int updateClaimStatusByAshaAndIncentiveIds( + @Param("ashaId") Integer ashaId, + @Param("isClaimed") Boolean isClaimed, + @Param("calimedDate") Timestamp calimedDate, + @Param("incentiveId") Long incentiveId + ); } diff --git a/src/main/java/com/iemr/flw/service/IncentiveService.java b/src/main/java/com/iemr/flw/service/IncentiveService.java index 01da2431e..ad7c122c9 100644 --- a/src/main/java/com/iemr/flw/service/IncentiveService.java +++ b/src/main/java/com/iemr/flw/service/IncentiveService.java @@ -22,4 +22,4 @@ public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boolean isClaimed, - String token);} + String token,String incentiveId);} diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 0c3deb78e..131080d1f 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -767,21 +767,42 @@ public String updateIncentive(PendingActivityDTO pendingActivityDTO) { // ================= UPDATE CLAIM ================= @Transactional - public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boolean isClaimed, String token) { + public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boolean isClaimed, String token,String incentive) { String title = null; try { LocalDate start = LocalDate.of(year, month, 1); LocalDate end = start.plusMonths(1); + int updated=0; + + Timestamp claimedDate = Timestamp.valueOf(LocalDateTime.now()); + + if (incentive == null || incentive.isEmpty()) { + + // No incentive IDs → all incentives for selected month/date range + updated = recordRepo.updateClaimStatusByAshaAndDateRange( + ashaId, + isClaimed, + claimedDate, + Timestamp.valueOf(start.atStartOfDay()), + Timestamp.valueOf(end.atStartOfDay()) + ); + + } else { + + for (String incentiveId : incentive.split(",")) { + + Long id = Long.parseLong(incentiveId.trim()); + updated = recordRepo.updateClaimStatusByAshaAndIncentiveIds( + ashaId, + isClaimed, + claimedDate,id + ); + } + } + + if (updated > 0) { - int updated = recordRepo.updateClaimStatusByAshaAndDateRange( - ashaId, - isClaimed, - Timestamp.valueOf(LocalDateTime.now()), - Timestamp.valueOf(start.atStartOfDay()), - Timestamp.valueOf(end.atStartOfDay()) - ); - if(updated>0){ Map data = new HashMap<>(); data.put("notification_type", "INCENTIVE_APPROVAL"); data.put("nav_id", "INCENTIVE_HISTORY"); @@ -791,31 +812,41 @@ public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boo data.put("year", String.valueOf(year)); data.put("approval_status", String.valueOf(102)); data.put("priority", "HIGH"); + title = "Incentive Claimed"; + if (isClaimed) { + String body = "Your incentive successfully claimed for month of " + + Month.of(month).name() + " " + year; - if (isClaimed) { - String body = "Your incentive Successfully claimed for month of" + Month.of(month).name() + " " + year; notificationService.sendNotification( - "FLW","NA" , + "FLW", + "NA", title, body, - "INCENTIVE_CLAIMED","INCENTIVE",ashaId + "INCENTIVE_CLAIMED", + "INCENTIVE", + ashaId ); - } - if (isClaimed) { - String body = userService.getUserDetail(ashaId).getName()+" Successfully claimed Incentive for month of " + Month.of(month).name() + " " + year; + + String supervisorBody = + userService.getUserDetail(ashaId).getName() + + " successfully claimed incentive for month of " + + Month.of(month).name() + + " " + + year; + notificationService.sendNotification( - "FLW","NA" , + "FLW", + "NA", title, - body, - "INCENTIVE_CLAIMED","INCENTIVE",dashboardRepo.getSupervisorUserIdByAshaId(ashaId) + supervisorBody, + "INCENTIVE_CLAIMED", + "INCENTIVE", + dashboardRepo.getSupervisorUserIdByAshaId(ashaId) ); } - - - } return updated > 0 ? "Success" : "No records"; From f96720ae3e9dcdc9db86198256e5b8fa966e407e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 31 Aug 2026 17:46:39 +0530 Subject: [PATCH 044/237] fix notification issue --- src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java | 3 +++ src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java | 3 +++ src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java | 3 +++ src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java | 2 ++ .../java/com/iemr/flw/service/impl/ChildCareServiceImpl.java | 3 ++- 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java b/src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java index 1513c0888..fa35c41e3 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java @@ -107,4 +107,7 @@ public class HbncVisit { @Column(name = "baby_eyes_swollen") private Boolean babyEyesSwollen; + @Column(name = "is_admitted_in_sncu") + private Boolean is_admitted_in_sncu; + }; diff --git a/src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java b/src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java index 7a22516fa..aee846efc 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java +++ b/src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java @@ -100,4 +100,7 @@ public class InfantRegister { @Column(name = "is_sncu") private String isSNCU; + + @Column(name = "is_Referred_higher_facility") + private Boolean isReferredHigherFacility; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java index 239e21c8f..d5cc8acf0 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java @@ -93,6 +93,9 @@ public class HbncVisitDTO { @Column(name = "baby_eyes_swollen") private Boolean babyEyesSwollen; + @Column(name = "is_admitted_in_sncu") + private Boolean is_admitted_in_sncu; + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java index 172132e07..9a983b508 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java @@ -119,4 +119,6 @@ public class HbycDTO { + + } diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 8db662b54..8a6f4362c 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -212,9 +212,10 @@ public List getHbycRecords(GetBenRequestHandler dto) { addIfValid(fields, "parenting_counseling", convert(hbycChildVisit.getParenting_counseling())); addIfValid(fields, "family_planning_counseling", convert(hbycChildVisit.getFamily_planning_counseling())); addIfValid(fields, "diarrhoea_episode", convert(hbycChildVisit.getDiarrhoea_episode())); -// addIfValid(fields, "breathing_difficulty", convert(hbycChildVisit.getBreathing_difficulty())); + addIfValid(fields, "breathing_difficulty", convert(hbycChildVisit.getBreathing_difficulty())); addIfValid(fields, "temperature_check", hbycChildVisit.getTemperature()); addIfValid(fields, "mcp_card_images", hbycChildVisit.getMcp_card_images()); + addIfValid(fields,"is_admitted_in_sncu",hbycChildVisit.getIs_child_sick()); // Set fields map in DTO From a7325a191842f76d61856c39aef09412b3777ae5 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 31 Aug 2026 17:53:24 +0530 Subject: [PATCH 045/237] fix notification issue --- .../java/com/iemr/flw/service/impl/ChildCareServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 8a6f4362c..a9f4190c8 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -215,7 +215,6 @@ public List getHbycRecords(GetBenRequestHandler dto) { addIfValid(fields, "breathing_difficulty", convert(hbycChildVisit.getBreathing_difficulty())); addIfValid(fields, "temperature_check", hbycChildVisit.getTemperature()); addIfValid(fields, "mcp_card_images", hbycChildVisit.getMcp_card_images()); - addIfValid(fields,"is_admitted_in_sncu",hbycChildVisit.getIs_child_sick()); // Set fields map in DTO @@ -280,6 +279,7 @@ public List getHBNCDetails(GetBenRequestHandler dto) { addIfValid(fields, "umbilical_stump", visit.getUmbilical_stump()); addIfValid(fields, "discharged_from_sncu", convert(visit.getDischarged_from_sncu())); addIfValid(fields, "discharge_summary_upload", visit.getDischarge_summary_upload()); + addIfValid(fields, "is_admitted_in_sncu", visit.getIs_admitted_in_sncu()); // Add more fields as required From efa59212b558f9610b85baf335664dc648147820 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 31 Aug 2026 17:54:26 +0530 Subject: [PATCH 046/237] fix notification issue --- .../java/com/iemr/flw/service/impl/ChildCareServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index a9f4190c8..fbc2cb00b 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -198,7 +198,7 @@ public List getHbycRecords(GetBenRequestHandler dto) { addIfValid(fields, "is_child_sick", convert(hbycChildVisit.getIs_child_sick())); addIfValid(fields, "exclusive_breastfeeding", convert(hbycChildVisit.getExclusive_breastfeeding())); addIfValid(fields, "mother_counseled_ebf", convert(hbycChildVisit.getMother_counseled_ebf())); -// addIfValid(fields, "complementary_feeding", convert(hbycChildVisit.getComplementary_feeding())); + addIfValid(fields, "complementary_feeding", convert(hbycChildVisit.getComplementary_feeding())); addIfValid(fields, "mother_counseled_cf", convert(hbycChildVisit.getMother_counseled_cf())); addIfValid(fields, "weight_recorded", convert(hbycChildVisit.getWeight_recorded())); addIfValid(fields, "developmental_delay", convert(hbycChildVisit.getDevelopmental_delay())); From d4fc20a02635933eaaf12c3c151a5952658c41d3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 31 Aug 2026 18:03:47 +0530 Subject: [PATCH 047/237] fix notification issue --- .../java/com/iemr/flw/service/impl/ChildCareServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index fbc2cb00b..6660b9b06 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -279,7 +279,7 @@ public List getHBNCDetails(GetBenRequestHandler dto) { addIfValid(fields, "umbilical_stump", visit.getUmbilical_stump()); addIfValid(fields, "discharged_from_sncu", convert(visit.getDischarged_from_sncu())); addIfValid(fields, "discharge_summary_upload", visit.getDischarge_summary_upload()); - addIfValid(fields, "is_admitted_in_sncu", visit.getIs_admitted_in_sncu()); + addIfValid(fields, "is_admitted_in_sncu", convert(visit.getIs_admitted_in_sncu())); // Add more fields as required From 2966632cfbc54b964d515fb3f37e51b9cf493699 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 13:03:18 +0530 Subject: [PATCH 048/237] fix rtd test incentive --- .../flw/service/impl/DiseaseControlServiceImpl.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java index 64bc90cf1..08caccd03 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java @@ -1268,6 +1268,16 @@ private void checkAndAddIncentives(ScreeningMalaria diseaseScreening) { } + }else { + if(!diseaseScreening.getMalariaTestType().isEmpty()){ + if (stateId.equals(StateCode.CG.getStateCode())) { + if (incentiveActivityForCollectSlideCG != null) { + addIncentive(incentiveActivityForCollectSlideCG, diseaseScreening); + + } + } + + } } if (diseaseScreening.getCaseStatus().equals("Suspected")) { if (!diseaseScreening.getMalariaTestType().isEmpty()) { From 04d713450a26ce5b88a8b858f3ec706b26c807d9 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 14:06:38 +0530 Subject: [PATCH 049/237] fix rtd test incentive --- .../flw/service/impl/CoupleServiceImpl.java | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java index e22147afa..fa92166d7 100644 --- a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java @@ -16,6 +16,7 @@ import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.CoupleService; import com.iemr.flw.service.UserService; +import org.joda.time.DateTime; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +27,8 @@ import java.io.IOException; import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -164,7 +167,7 @@ public String registerEligibleCouple(List eligibleCoupleDTOs, GroupName.FAMILY_PLANNING.getDisplayName()); if (activity != null) { - createIncentiveRecord(existingECR, activity); + createIncentiveRecordForKitHandOver(existingECR, activity); } } if(stateId.equals(StateCode.CG.getStateCode())){ @@ -174,7 +177,7 @@ public String registerEligibleCouple(List eligibleCoupleDTOs, GroupName.ACTIVITY.getDisplayName()); if (activity != null) { - createIncentiveRecord(existingECR, activity); + createIncentiveRecordForKitHandOver(existingECR, activity); } } @@ -391,6 +394,54 @@ record = new IncentiveActivityRecord(); + } + + private void createIncentiveRecordForKitHandOver(EligibleCoupleRegister eligibleCoupleDTO, IncentiveActivity activity) { + String lockKey = activity.getId() + "_" + eligibleCoupleDTO.getBenId() + "_" + eligibleCoupleDTO.getCreatedDate(); + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + if (activity == null + || eligibleCoupleDTO == null + || eligibleCoupleDTO.getKitHandedOverDate() == null + || eligibleCoupleDTO.getKitHandedOverDate().trim().isEmpty()) { + return; + } + + LocalDate kitHandOverDate = + LocalDate.parse(eligibleCoupleDTO.getKitHandedOverDate()); + + Timestamp kitHandOverTimestamp = + Timestamp.valueOf(kitHandOverDate.atStartOfDay()); + synchronized (lock){ + if (activity != null) { + if(eligibleCoupleDTO.getKitHandedOverDate()!=null && !eligibleCoupleDTO.getKitHandedOverDate().isEmpty()){ + + } + Integer userId = userRepo.getUserIdByName(eligibleCoupleDTO.getCreatedBy()); + + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), eligibleCoupleDTO.getCreatedDate(), eligibleCoupleDTO.getBenId(),userId); + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(kitHandOverTimestamp); + record.setCreatedBy(eligibleCoupleDTO.getCreatedBy()); + record.setStartDate(kitHandOverTimestamp); + record.setEndDate(kitHandOverTimestamp); + record.setUpdatedDate(eligibleCoupleDTO.getCreatedDate()); + record.setUpdatedBy(eligibleCoupleDTO.getCreatedBy()); + record.setBenId(eligibleCoupleDTO.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(activity.getRate())); + recordRepo.save(record); + } + } + } + lockMap.remove(lockKey, lock); + + + } @Override From c6642d2cf079234b726768a3f9eb7d16943213a7 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 14:41:16 +0530 Subject: [PATCH 050/237] fix rtd test incentive --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index c661b0ea7..d9c244f19 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -825,7 +825,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) ){ if(approvalStatusID.equals(102)){ - totalAmount = incentiveRecordRepo.getTotalAmountByAshaANM( + totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( ashaId, startDate, endDate, approvalStatusID, stateCode); }else if(approvalStatusID.equals(104)){ totalAmount = incentiveRecordRepo.getTotalAmountByAshaANM( From 20109812092276500086967a0a150dabca9887b7 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 14:59:58 +0530 Subject: [PATCH 051/237] fix rtd test incentive --- .../impl/SupervisorDashboardServiceImpl.java | 49 ++----------------- 1 file changed, 5 insertions(+), 44 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index d9c244f19..e09bd5f65 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -815,26 +815,12 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci ashaId, startDate, endDate, approvalStatusID, stateCode); }else if(stateCode.equals(StateCode.CG.getStateCode())){ if("ASHA Supervisor".equalsIgnoreCase(roleName)){ - if(approvalStatusID.equals(105)){ - totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( - ashaId, startDate, endDate, 101, stateCode); - }else { - totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( - ashaId, startDate, endDate, approvalStatusID, stateCode); - } + totalAmount = incentiveRecordRepo.getTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) ){ - if(approvalStatusID.equals(102)){ - totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( - ashaId, startDate, endDate, approvalStatusID, stateCode); - }else if(approvalStatusID.equals(104)){ - totalAmount = incentiveRecordRepo.getTotalAmountByAshaANM( - ashaId, startDate, endDate, 105, stateCode); - } else { - totalAmount = incentiveRecordRepo.getTotalAmountByAsha( - ashaId, startDate, endDate, approvalStatusID, stateCode); - } - + totalAmount = incentiveRecordRepo.getTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); } } @@ -878,32 +864,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - if (approvalStatusID.equals(102)) { - - incentiveActivityRecord = dbRecords.stream() - .peek(r -> { - if (r.getApprovalStatus().equals(102) - && r.getCalimedDate() != null - && isAfter24Hours(r.getCalimedDate())) { - - r.setApprovalStatus(105); - } - }) - .filter(r -> - r.getApprovalStatus().equals(105) - || (r.getApprovalStatus().equals(102))) - .collect(Collectors.toList()); - totalAmount = incentiveActivityRecord.stream() - .mapToLong(r -> r.getAmount()) - .sum(); - incentiveActivityRecord.forEach(r -> logger.info( - "activityId={}, status={}, isDefaultActivity={}", - r.getActivityId(), - r.getApprovalStatus(), - r.getIsDefaultActivity() - )); - - }else if (approvalStatusID.equals(104)) { + if (approvalStatusID.equals(104)) { if(isOverDue){ incentiveActivityRecord = dbRecords.stream() .filter(r -> From d061936482e9d92d31b21f6b90f3b87c64a7530e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 15:16:17 +0530 Subject: [PATCH 052/237] fix rtd test incentive --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 131080d1f..cb6f4f083 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -807,7 +807,7 @@ public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boo data.put("notification_type", "INCENTIVE_APPROVAL"); data.put("nav_id", "INCENTIVE_HISTORY"); data.put("sender_user_id", String.valueOf(ashaId)); - data.put("receiver_user_id", String.valueOf(ashaId)); + data.put("receiver_user_id", String.valueOf(dashboardRepo.getSupervisorUserIdByAshaId(ashaId))); data.put("month", String.valueOf(month)); data.put("year", String.valueOf(year)); data.put("approval_status", String.valueOf(102)); @@ -827,7 +827,7 @@ public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boo body, "INCENTIVE_CLAIMED", "INCENTIVE", - ashaId + dashboardRepo.getSupervisorUserIdByAshaId(ashaId) ); String supervisorBody = From 07c038a981c87b2e54963a8b1cc64da5bcd4cdea Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 16:02:11 +0530 Subject: [PATCH 053/237] fix rtd test incentive --- .../com/iemr/flw/service/impl/IncentiveServiceImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index cb6f4f083..73d5f9dc2 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -493,7 +493,11 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege && r.getEndDate() != null && r.getEndDate().toLocalDateTime().getMonthValue() == request.getMonth() && r.getEndDate().toLocalDateTime().getYear() == request.getYear() - && r.getApprovalStatus().equals(request.getApprovalStatus()) + && r.getApprovalStatus().equals( + request.getApprovalStatus().equals(104) + ? 102 + : request.getApprovalStatus() + ) && r.getIsClaimed()) .toList(); From 9e868210f97b9d2b1df563b23e629e27ba191978 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 16:03:13 +0530 Subject: [PATCH 054/237] fix rtd test incentive --- .../iemr/flw/service/impl/IncentiveServiceImpl.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 73d5f9dc2..f5c303fbf 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -493,10 +493,12 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege && r.getEndDate() != null && r.getEndDate().toLocalDateTime().getMonthValue() == request.getMonth() && r.getEndDate().toLocalDateTime().getYear() == request.getYear() - && r.getApprovalStatus().equals( - request.getApprovalStatus().equals(104) - ? 102 - : request.getApprovalStatus() + && ( + Objects.equals(request.getApprovalStatus(), 104) + ? (Objects.equals(r.getApprovalStatus(), 102) + || Objects.equals(r.getApprovalStatus(), 105)) + : Objects.equals(r.getApprovalStatus(), request.getApprovalStatus()) + ) && r.getIsClaimed()) .toList(); From 54a06eb4b4edfd985f65a78c70306ec4d4e5c138 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 16:10:01 +0530 Subject: [PATCH 055/237] fix rtd test incentive --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index e09bd5f65..cb499770c 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -868,7 +868,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if(isOverDue){ incentiveActivityRecord = dbRecords.stream() .filter(r -> - r.getApprovalStatus().equals(105) + r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(102) || (r.getApprovalStatus().equals(104))) .peek(r -> { if (r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(105)) { From 4f830c454b755704a9a7de787606c2ca57a0febb Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 16:27:32 +0530 Subject: [PATCH 056/237] fix rtd test incentive --- .../impl/SupervisorDashboardServiceImpl.java | 57 +++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index cb499770c..4d7fe870e 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -865,19 +865,66 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { if (approvalStatusID.equals(104)) { - if(isOverDue){ + + logger.info("Approval Status ID: {}, isOverDue: {}", approvalStatusID, isOverDue); + + // Before filtering + logger.info("Total dbRecords count: {}", dbRecords.size()); + + dbRecords.forEach(r -> + logger.info( + "DB Record -> id: {}, approvalStatus: {}, ashaId: {}, benId: {}, activityId: {}", + r.getId(), + r.getApprovalStatus(), + r.getAshaId(), + r.getBenId(), + r.getActivityId() + ) + ); + + if (isOverDue) { + incentiveActivityRecord = dbRecords.stream() .filter(r -> - r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(102) - || (r.getApprovalStatus().equals(104))) + Objects.equals(r.getApprovalStatus(), 105) + || Objects.equals(r.getApprovalStatus(), 102) + || Objects.equals(r.getApprovalStatus(), 104) + ) .peek(r -> { - if (r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(105)) { + logger.info( + "Matched Record -> id: {}, original approvalStatus: {}", + r.getId(), + r.getApprovalStatus() + ); + + if (Objects.equals(r.getApprovalStatus(), 102) + || Objects.equals(r.getApprovalStatus(), 105)) { + + logger.info( + "Changing approvalStatus for record id: {} from {} to 104", + r.getId(), + r.getApprovalStatus() + ); + r.setApprovalStatus(104); } }) .collect(Collectors.toList()); - } + logger.info("Filtered incentiveActivityRecord count: {}", + incentiveActivityRecord.size()); + + incentiveActivityRecord.forEach(r -> + logger.info( + "Final Record -> id: {}, approvalStatus: {}, ashaId: {}, benId: {}, activityId: {}", + r.getId(), + r.getApprovalStatus(), + r.getAshaId(), + r.getBenId(), + r.getActivityId() + ) + ); + } }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() .filter(r->!r.getIsClaimed() && r.getApprovalStatus().equals(102)).collect(Collectors.toList()); From e5eae5a6465a39b0bdb4974a4727c675b929c6ee Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 16:46:08 +0530 Subject: [PATCH 057/237] fix rtd test incentive --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 4d7fe870e..e04fb27e7 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1003,7 +1003,7 @@ && isAfter24Hours(r.getCalimedDate())) { - long pending = 0, verified = 0, rejected = 0 , unclaimedCount = 0 ; + long pending = 0, verified = 0, rejected = 0 , unclaimedCount = 0 , overDue ; if (countList != null && !countList.isEmpty()) { @@ -1091,7 +1091,7 @@ && isAfter24Hours(r.getCalimedDate())) { } - if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0) continue; + if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overallOverDue==0) continue; if (approvalStatusID.equals(0)) { asha.put("approvalStatus", approvalStatus); From 3129bbc82ba1015ac284fe5d63c0cdbc6d994328 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 16:56:05 +0530 Subject: [PATCH 058/237] fix rtd test incentive --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index e04fb27e7..2dbc2fea8 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1204,7 +1204,7 @@ public int updateApprovalStatus(Integer ashaId, if ("ASHA Supervisor".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())) { updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( - ashaId, 105, startDate, endDate, + ashaId, approvalStatus, startDate, endDate, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); From 0c5e41ef0de145ee5f87ac00bacaa6676cc3c364 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 17:20:40 +0530 Subject: [PATCH 059/237] fix rtd test incentive --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 2dbc2fea8..7953ae3bb 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -924,6 +924,11 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci r.getActivityId() ) ); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); } }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() @@ -1003,7 +1008,7 @@ && isAfter24Hours(r.getCalimedDate())) { - long pending = 0, verified = 0, rejected = 0 , unclaimedCount = 0 , overDue ; + long pending = 0, verified = 0, rejected = 0 , unclaimedCount = 0 , overDue = 0 ; if (countList != null && !countList.isEmpty()) { @@ -1262,7 +1267,7 @@ public int updateApprovalStatus(Integer ashaId, Long id = Long.parseLong(incentiveId.trim()); - updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveId(id, ashaId, 105, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveId(id, ashaId, approvalStatus, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); } } From f1f2496b682d8987f58e19680a0bf7657a0174dd Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 18:08:15 +0530 Subject: [PATCH 060/237] fix rtd test incentive --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 7953ae3bb..d5e8daee0 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -237,7 +237,7 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In List statusRows = dashboardRepo.getDefaultIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); if (statusRows != null) { for (Object[] sRow : statusRows) { - long verified = ((Number) sRow[5]).longValue(); + long verified = ((Number) sRow[2]).longValue(); long rejected = ((Number) sRow[3]).longValue(); long pending = ((Number) sRow[4]).longValue(); From 120036c0a3e86d4c240a21a70ef276d5401be75f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 18:11:50 +0530 Subject: [PATCH 061/237] fix rtd test incentive --- .../impl/SupervisorDashboardServiceImpl.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index d5e8daee0..4e12cd74e 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -851,6 +851,11 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveActivityRecord = dbRecords.stream() .filter(r ->r.getApprovalStatus().equals(102) && !r.getIsClaimed()) .collect(Collectors.toList()); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); }else if(approvalStatusID.equals(0)){ incentiveActivityRecord = dbRecords.stream() .filter(r ->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed())|| r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104))) @@ -933,6 +938,11 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() .filter(r->!r.getIsClaimed() && r.getApprovalStatus().equals(102)).collect(Collectors.toList()); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); }else if(approvalStatusID.equals(0)){ incentiveActivityRecord = dbRecords.stream() .filter(r->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed()) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104))).collect(Collectors.toList()); @@ -1090,10 +1100,7 @@ && isAfter24Hours(r.getCalimedDate())) { if (!activityList.isEmpty()) { approvalStatus = (int) activityList.get(0).get("approvalStatus"); } - if(!approvalStatusID.equals(106)){ - if (totalAmount == null || totalAmount <= 0) continue; - } if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overallOverDue==0) continue; From 74ef44826104d92838aca574011bae51605fb410 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 18:22:39 +0530 Subject: [PATCH 062/237] fix rtd test incentive --- .../com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java | 1 - .../flw/service/impl/SupervisorDashboardServiceImpl.java | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java index 071aeab0e..440cb65fa 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -164,7 +164,6 @@ List getIncentiveStatusByAshaIdsForAnm( + "WHERE iar.asha_id IN (:ashaIds) " + "AND iar.created_date >= :startDate " + "AND iar.is_claimed = true " - + "AND iar.is_default_activity = true " + "AND iar.created_date < :endDate " + "GROUP BY iar.asha_id", nativeQuery = true) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 4e12cd74e..5865fe9a2 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -847,6 +847,11 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveActivityRecord = dbRecords.stream() .filter(r -> (r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(105))) .collect(Collectors.toList()); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() .filter(r ->r.getApprovalStatus().equals(102) && !r.getIsClaimed()) @@ -863,7 +868,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else{ incentiveActivityRecord = dbRecords.stream() .filter(r ->( approvalStatusID == 0 || - approvalStatusID.equals(r.getApprovalStatus())) && r.getIsDefaultActivity() && isWithin24Hours(r.getCalimedDate())) + approvalStatusID.equals(r.getApprovalStatus()))) .collect(Collectors.toList()); } From 96e9cc71e8868a1908249708eee1d8f211b49c63 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 18:24:35 +0530 Subject: [PATCH 063/237] fix rtd test incentive --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 5865fe9a2..b47271d05 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -855,6 +855,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() .filter(r ->r.getApprovalStatus().equals(102) && !r.getIsClaimed()) + .peek(r->{r.setApprovalStatus(106);}) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) @@ -942,7 +943,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci } }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() - .filter(r->!r.getIsClaimed() && r.getApprovalStatus().equals(102)).collect(Collectors.toList()); + .filter(r->!r.getIsClaimed() && r.getApprovalStatus().equals(102)).peek(r->{r.setApprovalStatus(106);}).collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) .filter(Objects::nonNull) From ade97fa0013d3cf1673522439c08a1251863611d Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 18:34:56 +0530 Subject: [PATCH 064/237] fix rtd test incentive --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index b47271d05..3b805a404 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1106,6 +1106,9 @@ && isAfter24Hours(r.getCalimedDate())) { if (!activityList.isEmpty()) { approvalStatus = (int) activityList.get(0).get("approvalStatus"); } + if(!approvalStatusID.equals(106) && !facilityId.equals(0)){ + if (totalAmount == null || totalAmount <= 0) continue; + } From 78a2ac2f1ad4e9cf3b900e7035cbf4f8563a27b9 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 18:35:13 +0530 Subject: [PATCH 065/237] fix rtd test incentive --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 3b805a404..b797089b0 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1106,7 +1106,7 @@ && isAfter24Hours(r.getCalimedDate())) { if (!activityList.isEmpty()) { approvalStatus = (int) activityList.get(0).get("approvalStatus"); } - if(!approvalStatusID.equals(106) && !facilityId.equals(0)){ + if(!approvalStatusID.equals(106) || !facilityId.equals(0)){ if (totalAmount == null || totalAmount <= 0) continue; } From cf38689f9f9f9df9ded01b4f72a906d77879b037 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 18:46:11 +0530 Subject: [PATCH 066/237] fix approval status issuse --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index b797089b0..6988a7764 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1052,13 +1052,8 @@ && isAfter24Hours(r.getCalimedDate())) { }else if(roleName.equalsIgnoreCase("ASHA Supervisor")) { - if (approvalStatusID.equals(105)) { - // 101 + 105 - verified = counts[3] != null ? ((Number) counts[3]).longValue() : 0; - } else { - // only 101 - verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; - } + verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; + if(approvalStatusID.equals(106)){ unclaimedCount = counts[1] != null ? ((Number) counts[1]).longValue() : 0; From 864d9195bc3332f1049fa59c7a12bc8b8ca3751e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 18:54:03 +0530 Subject: [PATCH 067/237] fix approval status issuse --- .../com/iemr/flw/service/impl/IncentiveServiceImpl.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index f5c303fbf..62e86892d 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -499,7 +499,16 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege || Objects.equals(r.getApprovalStatus(), 105)) : Objects.equals(r.getApprovalStatus(), request.getApprovalStatus()) + + + + ) + && ( + Objects.equals(request.getApprovalStatus(), 105) + ? (Objects.equals(r.getApprovalStatus(), 101) + || Objects.equals(r.getApprovalStatus(), 105)) + : Objects.equals(r.getApprovalStatus(), request.getApprovalStatus())) && r.getIsClaimed()) .toList(); From d6df5ed4c88ed18620941ec193716bc99934c0c1 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 19:00:40 +0530 Subject: [PATCH 068/237] fix approval status issuse --- src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java b/src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java index 0be067ff8..d3cc280bf 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java @@ -37,4 +37,6 @@ public class InfantRegisterDTO { private String deliveryDischargeSummary3; private String deliveryDischargeSummary4; private String isSNCU; + private Boolean isReferredHigherFacility; + } From 9c0ef059cbeabb29b9f5e091487952b57d3b0c95 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 1 Sep 2026 19:05:50 +0530 Subject: [PATCH 069/237] fix approval status issuse --- .../service/impl/IncentiveServiceImpl.java | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 62e86892d..45348dcbb 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -489,27 +489,43 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege List records = recordRepo.findRecordsByAsha(request.getUserId()) .stream() - .filter(r -> r.getCreatedDate() != null - && r.getEndDate() != null - && r.getEndDate().toLocalDateTime().getMonthValue() == request.getMonth() - && r.getEndDate().toLocalDateTime().getYear() == request.getYear() + .filter(r -> + r.getCreatedDate() != null + && r.getEndDate() != null + && r.getEndDate().toLocalDateTime().getMonthValue() == request.getMonth() + && r.getEndDate().toLocalDateTime().getYear() == request.getYear() + && Boolean.TRUE.equals(r.getIsClaimed()) && ( - Objects.equals(request.getApprovalStatus(), 104) - ? (Objects.equals(r.getApprovalStatus(), 102) - || Objects.equals(r.getApprovalStatus(), 105)) - : Objects.equals(r.getApprovalStatus(), request.getApprovalStatus()) - - - - - + // 104 => 102 OR 105 + (Objects.equals(request.getApprovalStatus(), 104) + && ( + Objects.equals(r.getApprovalStatus(), 102) + || Objects.equals(r.getApprovalStatus(), 105) + ) + ) + + || + + // 105 => 101 OR 105 + (Objects.equals(request.getApprovalStatus(), 105) + && ( + Objects.equals(r.getApprovalStatus(), 101) + || Objects.equals(r.getApprovalStatus(), 105) + ) + ) + + || + + // Normal status + (!Objects.equals(request.getApprovalStatus(), 104) + && !Objects.equals(request.getApprovalStatus(), 105) + && Objects.equals( + r.getApprovalStatus(), + request.getApprovalStatus() + ) + ) + ) ) - && ( - Objects.equals(request.getApprovalStatus(), 105) - ? (Objects.equals(r.getApprovalStatus(), 101) - || Objects.equals(r.getApprovalStatus(), 105)) - : Objects.equals(r.getApprovalStatus(), request.getApprovalStatus())) - && r.getIsClaimed()) .toList(); From fa587206060816613783e9774b57ef4197ce8c8a Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 2 Sep 2026 16:33:26 +0530 Subject: [PATCH 070/237] fix approval status issuse --- .../java/com/iemr/flw/service/impl/CoupleServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java index fa92166d7..940166e86 100644 --- a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java @@ -338,7 +338,7 @@ private void checkIncentiveForChildGap(Integer stateId, String userName,List Date: Wed, 2 Sep 2026 16:40:34 +0530 Subject: [PATCH 071/237] fix approval status issuse --- .../com/iemr/flw/service/impl/UTPReronaPaymentJob.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java index a8d57b653..7a8e751ba 100644 --- a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java +++ b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java @@ -44,8 +44,12 @@ public class UTPReronaPaymentJob implements CommandLineRunner { @Override public void run(String... args) { - log.info("Running UTP Rerona Payment Job on startup..."); - triggerStaticPayment(); + log.info("========================================"); + + log.info("FLW application started successfully and is now running."); + + log.info("========================================"); + } // ✅ Separate method — call this for immediate testing From 6b89600536cd936894a6d763f42bb1c9e33cb913 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 2 Sep 2026 17:14:24 +0530 Subject: [PATCH 072/237] fix approval status issuse --- src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java index 940166e86..b650dd430 100644 --- a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java @@ -420,7 +420,7 @@ private void createIncentiveRecordForKitHandOver(EligibleCoupleRegister eligible Integer userId = userRepo.getUserIdByName(eligibleCoupleDTO.getCreatedBy()); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(activity.getId(), eligibleCoupleDTO.getCreatedDate(), eligibleCoupleDTO.getBenId(),userId); + .findRecordByActivityIdCreatedDateBenId(activity.getId(), kitHandOverTimestamp, eligibleCoupleDTO.getBenId(),userId); if (record == null) { record = new IncentiveActivityRecord(); From 11d05c67a93216753a66074ca5d11b5cc45f8646 Mon Sep 17 00:00:00 2001 From: vishwab1 Date: Thu, 3 Sep 2026 15:12:45 +0530 Subject: [PATCH 073/237] fix: resolve IDOR vulnerability by extracting userId from JWT token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-picked from vb/release-3.8.1 (c24f32b9), adapted for the current tree: - getUserDetail (UserController): remove userId request param, extract from JwtToken header - getAll (MicroBirthPlanController): remove userId request param, extract from JwtToken header - getProfile (AshaProfileController): drop the unused/unbound employeeId param and dead JWT-validation duplicate, use jwtUtil.extractUserId(jwtToken) directly (functionally this path already used JWT-derived userId, not the param, before this cherry-pick — this cleans up the dead/confusing code to match) (cherry picked from commit c24f32b938d2e92261bb4227a52ed0edfe5c0a0c) --- .../flw/controller/AshaProfileController.java | 30 ++++--------------- .../controller/MicroBirthPlanController.java | 21 +++++-------- .../iemr/flw/controller/UserController.java | 10 +++++-- 3 files changed, 20 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/AshaProfileController.java b/src/main/java/com/iemr/flw/controller/AshaProfileController.java index 2d02ce231..e0a6510a4 100644 --- a/src/main/java/com/iemr/flw/controller/AshaProfileController.java +++ b/src/main/java/com/iemr/flw/controller/AshaProfileController.java @@ -3,9 +3,7 @@ import com.iemr.flw.domain.iemr.AshaWorker; import com.iemr.flw.service.AshaProfileService; import com.iemr.flw.service.EmployeeMasterInter; -import io.lettuce.core.dynamic.annotation.Param; import com.iemr.flw.utils.JwtUtil; -import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -56,33 +54,15 @@ public ResponseEntity> editEmployee(@RequestBody AshaWorker } @RequestMapping(value = "getProfile", method = RequestMethod.GET) - public ResponseEntity> getProfile(HttpServletRequest request, @Param("employeeId") Integer employeeId) { + public ResponseEntity> getProfile( + @RequestHeader(value = "JwtToken") String jwtToken) { Map response = new HashMap<>(); try { - String jwtFromHeader = request.getHeader("JwtToken"); - -// Validate JWT header presence - if (jwtFromHeader == null || jwtFromHeader.trim().isEmpty()) { - response.put("statusCode", 401); - response.put("status", "Unauthorized"); - response.put("errorMessage", "JWT token is missing"); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); - } - - // Extract and validate user ID from JWT - int userId = jwtUtil.extractUserId(jwtFromHeader); // Make sure this returns 0 or throws for invalid token - - if (userId == 0) { - response.put("statusCode", 401); - response.put("status", "Unauthorized"); - response.put("errorMessage", "Invalid JWT token"); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); - } + Integer employeeId = jwtUtil.extractUserId(jwtToken); - // Business logic - AshaWorker ashaWorker = ashaProfileService.getProfileData(userId); - logger.info("Asha Profile"+ashaWorker); + AshaWorker ashaWorker = ashaProfileService.getProfileData(employeeId); + logger.info("Asha Profile" + ashaWorker); response.put("statusCode", 200); response.put("status", "Success"); diff --git a/src/main/java/com/iemr/flw/controller/MicroBirthPlanController.java b/src/main/java/com/iemr/flw/controller/MicroBirthPlanController.java index c501b4054..a5fb0afa8 100644 --- a/src/main/java/com/iemr/flw/controller/MicroBirthPlanController.java +++ b/src/main/java/com/iemr/flw/controller/MicroBirthPlanController.java @@ -56,26 +56,21 @@ public ResponseEntity> createMicroBirthPlan(@RequestBody Mic @RequestMapping(value = "getAll", method = RequestMethod.GET) - public ResponseEntity> getAllMicroBirthPlans(@RequestParam("userId") Integer userId) { + public ResponseEntity> getAllMicroBirthPlans( + @RequestHeader(value = "JwtToken") String jwtToken) { Map response = new HashMap<>(); - - Map data = new HashMap<>(); try { - if (userId != null) { - data.put("userId", userId); - data.put("entries", service.getAllMicroBirthPlans(userId)); - response.put("data", data); - response.put("statusCode", 200); - response.put("status", "Success"); - } - + Integer userId = jwtUtil.extractUserId(jwtToken); + data.put("userId", userId); + data.put("entries", service.getAllMicroBirthPlans(userId)); + response.put("data", data); + response.put("statusCode", 200); + response.put("status", "Success"); } catch (Exception e) { response.put("statusCode", 500); response.put("errorMessage", e.getMessage()); - - } return ResponseEntity.ok(response); diff --git a/src/main/java/com/iemr/flw/controller/UserController.java b/src/main/java/com/iemr/flw/controller/UserController.java index 605bc0ddf..2ae329227 100644 --- a/src/main/java/com/iemr/flw/controller/UserController.java +++ b/src/main/java/com/iemr/flw/controller/UserController.java @@ -3,13 +3,13 @@ import com.iemr.flw.dto.iemr.UserServiceRoleDTO; import com.iemr.flw.service.UserService; import com.iemr.flw.utils.ApiResponse; +import com.iemr.flw.utils.JwtUtil; import io.swagger.v3.oas.annotations.Operation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -23,11 +23,15 @@ public class UserController { @Autowired private UserService userService; + @Autowired + private JwtUtil jwtUtil; + @Operation(summary = "get user Detail of userId and roleId") @RequestMapping(value = { "/getUserDetail" }, method = { RequestMethod.GET }) - public ResponseEntity getUserDetail(@RequestParam(value = "userId") Integer userId, - @RequestHeader(value = "Authorization") String Authorization) { + public ResponseEntity getUserDetail( + @RequestHeader(value = "JwtToken") String jwtToken) { try { + Integer userId = jwtUtil.extractUserId(jwtToken); UserServiceRoleDTO result = userService.getUserDetail(userId); return new ResponseEntity<>( new ApiResponse(true, null, result), HttpStatus.ACCEPTED); From 51dcdbc5717bd1f726e0000c49846eed9d13c4cc Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 7 Sep 2026 15:00:27 +0530 Subject: [PATCH 074/237] fix approval status issuse --- .../domain/iemr/IncentiveActivityRecord.java | 3 + .../iemr/flw/dto/iemr/IncentiveRecordDTO.java | 1 + .../flw/repo/iemr/IncentiveRecordRepo.java | 1 + .../repo/iemr/SupervisorDashboardRepo.java | 1 + .../service/impl/IncentiveServiceImpl.java | 2 +- .../impl/SupervisorDashboardServiceImpl.java | 86 +++++++------------ 6 files changed, 40 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java index 67cb9af3a..88cebcfc6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java @@ -89,4 +89,7 @@ public class IncentiveActivityRecord { private String groupName; @Transient String groupCategoryName; + + @Column(name = "is_approved") + private boolean isApproved; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java index 6f9cd63d2..b3d0745f8 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java @@ -61,6 +61,7 @@ public class IncentiveRecordDTO { private String supervisorRole; + private boolean isApproved; diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index fac16c221..738a9d452 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -219,6 +219,7 @@ Long getTotalAmountByAshaANMbeforeClaimedHour( "WHERE record.ashaId = :ashaId " + "AND master.state = :stateCode " + "AND record.isClaimed = true " + + "AND record.isDefaultActivity = true " + "AND record.startDate >= :fromDate " + "AND record.endDate <= :toDate " + "AND (" + diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java index 440cb65fa..071aeab0e 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -164,6 +164,7 @@ List getIncentiveStatusByAshaIdsForAnm( + "WHERE iar.asha_id IN (:ashaIds) " + "AND iar.created_date >= :startDate " + "AND iar.is_claimed = true " + + "AND iar.is_default_activity = true " + "AND iar.created_date < :endDate " + "GROUP BY iar.asha_id", nativeQuery = true) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 45348dcbb..40558b32b 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -542,7 +542,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege if(isCG){ if("ASHA Supervisor".equalsIgnoreCase(roleName)){ records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) + .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) .collect(Collectors.toList()); }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 6988a7764..b09de3f80 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -237,7 +237,7 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In List statusRows = dashboardRepo.getDefaultIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); if (statusRows != null) { for (Object[] sRow : statusRows) { - long verified = ((Number) sRow[2]).longValue(); + long verified = ((Number) sRow[5]).longValue(); long rejected = ((Number) sRow[3]).longValue(); long pending = ((Number) sRow[4]).longValue(); @@ -246,24 +246,14 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In if (rejected > 0) overallRejected += 1; if (pending > 0) overallPending += 1; - if (overallPending > 0) { - try { - String title = "Pending Incentive Claims"; - - String body = "You have " + overallPending + " pending incentive claim(s) for " - + Month.of(month).name() + " " + year + ". Please review them."; - -// notificationService.sendNotification( -// "FLW", "NA", -// title, -// body, -// "INCENTIVE_PENDING", -// "INCENTIVE", -// supervisorUserID); - } catch (Exception ex) { - logger.error("Failed to send pending incentive notification for ashaId {}: {}", supervisorUserID, ex.getMessage(), ex); + if (pending > 0) { + if (isOverDue) { + overallOverDue++; + } else { + overallPending++; } } + } } }else if("ANM".equalsIgnoreCase(rollName)){ @@ -284,24 +274,6 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In } } - if (overallPending > 0) { - try { - String title = "Pending Incentive Claims"; - - String body = "You have " + overallPending + " pending incentive claim(s) for " - + Month.of(month).name() + " " + year + ". Please review them."; - -// notificationService.sendNotification( -// "FLW", "NA", -// title, -// body, -// "INCENTIVE_PENDING", -// "INCENTIVE", -// supervisorUserID); - } catch (Exception ex) { - logger.error("Failed to send pending incentive notification for ashaId {}: {}", supervisorUserID, ex.getMessage(), ex); - } - } } } } @@ -561,6 +533,14 @@ public String getSupervisorSubCenter(Integer supervisorUserID, Integer month, In if (verified > 0) overallVerified += 1; if (rejected > 0) overallRejected += 1; if (pending > 0) overallPending += 1; + + if (pending > 0) { + if (isOverDue) { + overallOverDue++; + } else { + overallPending++; + } + } } } }else if("ANM".equalsIgnoreCase(rollName)){ @@ -775,6 +755,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci countList = incentiveRecordRepo.getStatusUnclaimedCountByAshaId(ashaId, startDate, endDate); }else { + countList = incentiveRecordRepo.getStatusCountByAshaIdOfDefaultActivity(ashaId, startDate, endDate); countList = incentiveRecordRepo .getStatusCountByAshaId( @@ -815,7 +796,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci ashaId, startDate, endDate, approvalStatusID, stateCode); }else if(stateCode.equals(StateCode.CG.getStateCode())){ if("ASHA Supervisor".equalsIgnoreCase(roleName)){ - totalAmount = incentiveRecordRepo.getTotalAmountByAsha( + totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( ashaId, startDate, endDate, approvalStatusID, stateCode); }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName) ){ @@ -845,17 +826,11 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if("ASHA Supervisor".equalsIgnoreCase(roleName)){ if(approvalStatusID.equals(105)){ incentiveActivityRecord = dbRecords.stream() - .filter(r -> (r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(105))) + .filter(r -> (r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(105)) && r.getIsDefaultActivity()) .collect(Collectors.toList()); - totalAmount = incentiveActivityRecord.stream() - .map(IncentiveActivityRecord::getAmount) - .filter(Objects::nonNull) - .mapToLong(Long::longValue) - .sum(); }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() - .filter(r ->r.getApprovalStatus().equals(102) && !r.getIsClaimed()) - .peek(r->{r.setApprovalStatus(106);}) + .filter(r ->r.getApprovalStatus().equals(102) && r.getIsDefaultActivity() && !r.getIsClaimed()) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) @@ -864,23 +839,28 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .sum(); }else if(approvalStatusID.equals(0)){ incentiveActivityRecord = dbRecords.stream() - .filter(r ->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed())|| r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104))) + .filter(r ->(r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104)) && r.getIsDefaultActivity() && !r.getIsClaimed()) .collect(Collectors.toList()); }else{ incentiveActivityRecord = dbRecords.stream() .filter(r ->( approvalStatusID == 0 || - approvalStatusID.equals(r.getApprovalStatus()))) + approvalStatusID.equals(r.getApprovalStatus())) && r.getIsDefaultActivity() && isWithin24Hours(r.getCalimedDate())) .collect(Collectors.toList()); } }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - - if (approvalStatusID.equals(104)) { - - logger.info("Approval Status ID: {}, isOverDue: {}", approvalStatusID, isOverDue); - - // Before filtering - logger.info("Total dbRecords count: {}", dbRecords.size()); + if (approvalStatusID.equals(102)) { + incentiveActivityRecord = dbRecords.stream() + .filter(r -> + r.getApprovalStatus().equals(105) + || (r.getApprovalStatus().equals(102))) + .peek(r -> { + if (r.getApprovalStatus().equals(102) + && isAfter24Hours(r.getCalimedDate())) { + r.setApprovalStatus(105); + } + }) + .collect(Collectors.toList()); dbRecords.forEach(r -> logger.info( From 5df055783eb34bd9a458f66aaee2ca03a46d01e8 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 7 Sep 2026 15:32:46 +0530 Subject: [PATCH 075/237] fix approval status issuse --- .../com/iemr/flw/domain/iemr/IncentiveActivityRecord.java | 2 +- .../com/iemr/flw/service/impl/IncentiveServiceImpl.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java index 88cebcfc6..d36f4865a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java @@ -91,5 +91,5 @@ public class IncentiveActivityRecord { @Transient String groupCategoryName; @Column(name = "is_approved") - private boolean isApproved; + private Boolean isApproved; } diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 40558b32b..8d3ee8f42 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -578,6 +578,11 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) .map(IncentiveActivityRecord::getApprovalStatus) .orElse(0); + + boolean isApproved = list.stream() + .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) + .map(IncentiveActivityRecord::getIsApproved) + .orElse(false); Long incentiveId = list.stream() .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) .map(IncentiveActivityRecord::getId) @@ -603,6 +608,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege } map.put("isDefault", activity.getIsDefaultActivity()); map.put("approvalStatus", approvalStatus); + map.put("isApproved", isApproved); map.put("claimCount", list.size()); map.put("totalAmount", total); map.put("amount", activity.getRate()); From 3d36b142876f06789b4197fbc220a4a3ce6096c2 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 7 Sep 2026 15:34:03 +0530 Subject: [PATCH 076/237] fix approval status issuse --- src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java index b3d0745f8..e2a6787c1 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java @@ -61,7 +61,7 @@ public class IncentiveRecordDTO { private String supervisorRole; - private boolean isApproved; + private Boolean isApproved; From 608fce6a128c5d6cbd3d9fa9f14c91e09b1cbe5d Mon Sep 17 00:00:00 2001 From: vaibhav45sktech <232676907+vaibhav45sktech@users.noreply.github.com> Date: Mon, 7 Sep 2026 16:12:22 +0530 Subject: [PATCH 077/237] feat(badges): config, freezes and earned-log endpoints for SAKHI badges GET /badges/{config,freezes,earned} and POST /badges/earned; the ASHA is taken from the JWT, re-uploads are idempotent, defaults seeded on boot. --- .../iemr/flw/controller/BadgeController.java | 108 ++++++++++++++++++ .../com/iemr/flw/domain/iemr/BadgeConfig.java | 28 +++++ .../com/iemr/flw/domain/iemr/BadgeEarned.java | 45 ++++++++ .../flw/domain/iemr/BadgeStreakFreeze.java | 37 ++++++ .../com/iemr/flw/dto/iemr/BadgeEarnedDTO.java | 15 +++ .../iemr/flw/dto/iemr/BadgeEarnedPushDTO.java | 15 +++ .../iemr/flw/repo/iemr/BadgeConfigRepo.java | 9 ++ .../iemr/flw/repo/iemr/BadgeEarnedRepo.java | 14 +++ .../flw/repo/iemr/BadgeStreakFreezeRepo.java | 13 +++ .../iemr/flw/seeder/BadgeConfigSeeder.java | 49 ++++++++ .../com/iemr/flw/service/BadgeService.java | 74 ++++++++++++ .../flw/controller/BadgeControllerTest.java | 89 +++++++++++++++ .../iemr/flw/service/BadgeServiceTest.java | 55 +++++++++ 13 files changed, 551 insertions(+) create mode 100644 src/main/java/com/iemr/flw/controller/BadgeController.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/BadgeConfig.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/BadgeEarned.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/BadgeStreakFreeze.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedPushDTO.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/BadgeConfigRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/BadgeEarnedRepo.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/BadgeStreakFreezeRepo.java create mode 100644 src/main/java/com/iemr/flw/seeder/BadgeConfigSeeder.java create mode 100644 src/main/java/com/iemr/flw/service/BadgeService.java create mode 100644 src/test/java/com/iemr/flw/controller/BadgeControllerTest.java create mode 100644 src/test/java/com/iemr/flw/service/BadgeServiceTest.java diff --git a/src/main/java/com/iemr/flw/controller/BadgeController.java b/src/main/java/com/iemr/flw/controller/BadgeController.java new file mode 100644 index 000000000..aa5fb4855 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/BadgeController.java @@ -0,0 +1,108 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.iemr.BadgeEarnedPushDTO; +import com.iemr.flw.service.BadgeService; +import com.iemr.flw.utils.JwtUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +/** + * Badges API consumed by the SAKHI app's BadgeSyncWorker: + * GET /badges/config -> { "config": { key: value } } + * GET /badges/freezes -> { "freezes": [ { badgeId, startDate, endDate } ] } + * GET /badges/earned -> { "earned": [ { badgeId, level, earnedAt } ] } + * POST /badges/earned <- { userId, badges: [ { badgeId, level, earnedAt } ] } + * The ASHA is always identified from the JWT, never from the payload. + */ +@RestController +@RequestMapping(value = "/badges", produces = "application/json") +public class BadgeController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + private final BadgeService badgeService; + private final JwtUtil jwtUtil; + + public BadgeController(BadgeService badgeService, JwtUtil jwtUtil) { + this.badgeService = badgeService; + this.jwtUtil = jwtUtil; + } + + @GetMapping("/config") + public ResponseEntity> getConfig() { + Map response = ok(); + try { + response.put("config", badgeService.getConfig()); + return ResponseEntity.ok(response); + } catch (Exception e) { + return error(e); + } + } + + @GetMapping("/freezes") + public ResponseEntity> getFreezes( + @RequestHeader(value = "JwtToken") String jwtToken) { + Map response = ok(); + try { + Integer userId = jwtUtil.extractUserId(jwtToken); + response.put("freezes", badgeService.getFreezes(userId)); + return ResponseEntity.ok(response); + } catch (Exception e) { + return error(e); + } + } + + @GetMapping("/earned") + public ResponseEntity> getEarned( + @RequestHeader(value = "JwtToken") String jwtToken) { + Map response = ok(); + try { + Integer userId = jwtUtil.extractUserId(jwtToken); + response.put("earned", badgeService.getEarned(userId)); + return ResponseEntity.ok(response); + } catch (Exception e) { + return error(e); + } + } + + @PostMapping(value = "/earned", consumes = "application/json") + public ResponseEntity> postEarned( + @RequestHeader(value = "JwtToken") String jwtToken, + @RequestBody BadgeEarnedPushDTO body) { + Map response = ok(); + try { + Integer userId = jwtUtil.extractUserId(jwtToken); + int inserted = badgeService.saveEarned(userId, body == null ? null : body.getBadges()); + response.put("inserted", inserted); + return ResponseEntity.ok(response); + } catch (Exception e) { + return error(e); + } + } + + private Map ok() { + Map response = new HashMap<>(); + response.put("statusCode", 200); + response.put("status", "Success"); + return response; + } + + private ResponseEntity> error(Exception e) { + logger.error("Badges API error:", e); + Map response = new HashMap<>(); + response.put("statusCode", 500); + response.put("status", "Error"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/BadgeConfig.java b/src/main/java/com/iemr/flw/domain/iemr/BadgeConfig.java new file mode 100644 index 000000000..909871114 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/BadgeConfig.java @@ -0,0 +1,28 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Badge tuning as key/value rows (Badge LLD §5.2). Overrides the app's + * compiled defaults without a release, e.g. "milestones.steady_syncer" -> "2,4,6,8". + */ +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "badge_config", schema = "db_iemr") +public class BadgeConfig { + + @Id + @Column(name = "config_key", length = 100) + private String key; + + @Column(name = "config_value", length = 500, nullable = false) + private String value; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/BadgeEarned.java b/src/main/java/com/iemr/flw/domain/iemr/BadgeEarned.java new file mode 100644 index 000000000..b73864257 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/BadgeEarned.java @@ -0,0 +1,45 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import lombok.Data; + +/** + * Append-only badge award log (Badge LLD §4.1, "once earned, never revoked"). + * The unique key mirrors the device's local constraint so re-uploads after a + * reinstall or a retried sync are idempotent. + */ +@Entity +@Data +@Table(name = "badge_earned", schema = "db_iemr", + uniqueConstraints = @UniqueConstraint( + name = "uk_badge_earned_user_badge_level", + columnNames = {"user_id", "badge_id", "level"})) +public class BadgeEarned { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "badge_id", length = 50, nullable = false) + private String badgeId; + + @Column(name = "level", nullable = false) + private Integer level; + + /** Epoch millis when the device awarded it. */ + @Column(name = "earned_at", nullable = false) + private Long earnedAt; + + /** Epoch millis when the server first received it. */ + @Column(name = "received_at", nullable = false) + private Long receivedAt; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/BadgeStreakFreeze.java b/src/main/java/com/iemr/flw/domain/iemr/BadgeStreakFreeze.java new file mode 100644 index 000000000..afc7a9870 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/BadgeStreakFreeze.java @@ -0,0 +1,37 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; + +/** + * Streak-freeze window (Badge LLD §3.3): illness / alternate duty. A null userId + * applies to every ASHA; a null or empty badgeId applies to every streak badge. + */ +@Entity +@Data +@Table(name = "badge_streak_freeze", schema = "db_iemr") +public class BadgeStreakFreeze { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "user_id") + private Integer userId; + + @Column(name = "badge_id", length = 50) + private String badgeId; + + /** Epoch millis, inclusive. */ + @Column(name = "start_date", nullable = false) + private Long startDate; + + /** Epoch millis, inclusive. */ + @Column(name = "end_date", nullable = false) + private Long endDate; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedDTO.java b/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedDTO.java new file mode 100644 index 000000000..9ce8d6a79 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedDTO.java @@ -0,0 +1,15 @@ +package com.iemr.flw.dto.iemr; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** Wire shape shared with the app's BadgeEarnedDTO (Moshi). */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BadgeEarnedDTO { + private String badgeId; + private Integer level; + private Long earnedAt; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedPushDTO.java b/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedPushDTO.java new file mode 100644 index 000000000..dddca01c1 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedPushDTO.java @@ -0,0 +1,15 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +import java.util.List; + +/** + * POST /badges/earned body. The userId field is accepted for wire compatibility + * but never trusted: the owner is always taken from the JWT. + */ +@Data +public class BadgeEarnedPushDTO { + private Integer userId; + private List badges; +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/BadgeConfigRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BadgeConfigRepo.java new file mode 100644 index 000000000..0341fa8f1 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/BadgeConfigRepo.java @@ -0,0 +1,9 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.BadgeConfig; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BadgeConfigRepo extends JpaRepository { +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/BadgeEarnedRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BadgeEarnedRepo.java new file mode 100644 index 000000000..219571a55 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/BadgeEarnedRepo.java @@ -0,0 +1,14 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.BadgeEarned; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface BadgeEarnedRepo extends JpaRepository { + List findByUserIdOrderByEarnedAtAsc(Integer userId); + + boolean existsByUserIdAndBadgeIdAndLevel(Integer userId, String badgeId, Integer level); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/BadgeStreakFreezeRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BadgeStreakFreezeRepo.java new file mode 100644 index 000000000..adc063d94 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/BadgeStreakFreezeRepo.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.BadgeStreakFreeze; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface BadgeStreakFreezeRepo extends JpaRepository { + /** Global windows (user_id IS NULL) plus this ASHA's own. */ + List findByUserIdIsNullOrUserId(Integer userId); +} diff --git a/src/main/java/com/iemr/flw/seeder/BadgeConfigSeeder.java b/src/main/java/com/iemr/flw/seeder/BadgeConfigSeeder.java new file mode 100644 index 000000000..1c83833a5 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/BadgeConfigSeeder.java @@ -0,0 +1,49 @@ +package com.iemr.flw.seeder; + +import com.iemr.flw.domain.iemr.BadgeConfig; +import com.iemr.flw.repo.iemr.BadgeConfigRepo; +import jakarta.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Seeds the default badge tuning once (table empty). Values mirror the app's + * compiled defaults so a fresh server changes nothing until someone edits a row. + */ +@Component +public class BadgeConfigSeeder { + + private static final Logger log = LoggerFactory.getLogger(BadgeConfigSeeder.class); + + private final BadgeConfigRepo repo; + + public BadgeConfigSeeder(BadgeConfigRepo repo) { + this.repo = repo; + } + + @PostConstruct + public void seed() { + try { + if (repo.count() > 0) return; + repo.saveAll(List.of( + new BadgeConfig("feature_enabled", "true"), + new BadgeConfig("copy_version", "1"), + new BadgeConfig("milestones.steady_syncer", "2,4,6,8"), + new BadgeConfig("grace.steady_syncer", "1"), + new BadgeConfig("milestones.timely_reporter", "1,3,6,12"), + new BadgeConfig("milestones.complete_worker", "3"), + new BadgeConfig("milestones.community_voice", "2"), + new BadgeConfig("milestones.maternal_journey", "1,5,15,30"), + new BadgeConfig("milestones.child_fully_protected", "3,10,25,60"), + new BadgeConfig("milestones.digital_identity", "10,25,75,150"), + new BadgeConfig("enabled.critical_referral", "false") + )); + log.info("Badge config defaults seeded"); + } catch (Exception e) { + log.warn("Badge config seeding skipped: {}", e.getMessage()); + } + } +} diff --git a/src/main/java/com/iemr/flw/service/BadgeService.java b/src/main/java/com/iemr/flw/service/BadgeService.java new file mode 100644 index 000000000..074ad878e --- /dev/null +++ b/src/main/java/com/iemr/flw/service/BadgeService.java @@ -0,0 +1,74 @@ +package com.iemr.flw.service; + +import com.iemr.flw.domain.iemr.BadgeConfig; +import com.iemr.flw.domain.iemr.BadgeEarned; +import com.iemr.flw.domain.iemr.BadgeStreakFreeze; +import com.iemr.flw.dto.iemr.BadgeEarnedDTO; +import com.iemr.flw.repo.iemr.BadgeConfigRepo; +import com.iemr.flw.repo.iemr.BadgeEarnedRepo; +import com.iemr.flw.repo.iemr.BadgeStreakFreezeRepo; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Badges backend (Badge LLD §4). The device owns evaluation; the server only + * distributes tuning + freeze windows and keeps the durable award log so a + * reinstall restores progress. + */ +@Service +public class BadgeService { + + private final BadgeConfigRepo configRepo; + private final BadgeStreakFreezeRepo freezeRepo; + private final BadgeEarnedRepo earnedRepo; + + public BadgeService(BadgeConfigRepo configRepo, BadgeStreakFreezeRepo freezeRepo, + BadgeEarnedRepo earnedRepo) { + this.configRepo = configRepo; + this.freezeRepo = freezeRepo; + this.earnedRepo = earnedRepo; + } + + public Map getConfig() { + Map out = new LinkedHashMap<>(); + for (BadgeConfig row : configRepo.findAll()) { + out.put(row.getKey(), row.getValue()); + } + return out; + } + + public List getFreezes(Integer userId) { + return freezeRepo.findByUserIdIsNullOrUserId(userId); + } + + public List getEarned(Integer userId) { + return earnedRepo.findByUserIdOrderByEarnedAtAsc(userId).stream() + .map(e -> new BadgeEarnedDTO(e.getBadgeId(), e.getLevel(), e.getEarnedAt())) + .toList(); + } + + /** Idempotent: rows already known for (user, badge, level) are skipped. Returns rows inserted. */ + @Transactional + public int saveEarned(Integer userId, List badges) { + if (badges == null || badges.isEmpty()) return 0; + long now = System.currentTimeMillis(); + int inserted = 0; + for (BadgeEarnedDTO dto : badges) { + if (dto == null || dto.getBadgeId() == null || dto.getLevel() == null) continue; + if (earnedRepo.existsByUserIdAndBadgeIdAndLevel(userId, dto.getBadgeId(), dto.getLevel())) continue; + BadgeEarned row = new BadgeEarned(); + row.setUserId(userId); + row.setBadgeId(dto.getBadgeId()); + row.setLevel(dto.getLevel()); + row.setEarnedAt(dto.getEarnedAt() != null ? dto.getEarnedAt() : now); + row.setReceivedAt(now); + earnedRepo.save(row); + inserted++; + } + return inserted; + } +} diff --git a/src/test/java/com/iemr/flw/controller/BadgeControllerTest.java b/src/test/java/com/iemr/flw/controller/BadgeControllerTest.java new file mode 100644 index 000000000..bb6069936 --- /dev/null +++ b/src/test/java/com/iemr/flw/controller/BadgeControllerTest.java @@ -0,0 +1,89 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.iemr.BadgeEarnedDTO; +import com.iemr.flw.service.BadgeService; +import com.iemr.flw.utils.JwtUtil; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class BadgeControllerTest { + + private MockMvc mockMvc; + + @Mock + private BadgeService badgeService; + + @Mock + private JwtUtil jwtUtil; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(new BadgeController(badgeService, jwtUtil)).build(); + } + + @Test + void config_returnsKeyValueMapUnderConfig() throws Exception { + when(badgeService.getConfig()).thenReturn(Map.of("milestones.steady_syncer", "2,4,6,8")); + + mockMvc.perform(get("/badges/config")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.config['milestones.steady_syncer']").value("2,4,6,8")); + } + + @Test + void earned_usesUserIdFromJwtNotFromBody() throws Exception { + when(jwtUtil.extractUserId("tok")).thenReturn(960); + when(badgeService.saveEarned(eq(960), any())).thenReturn(1); + + mockMvc.perform(post("/badges/earned") + .header("JwtToken", "tok") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"userId\":12345,\"badges\":[{\"badgeId\":\"steady_syncer\",\"level\":2,\"earnedAt\":1}]}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.inserted").value(1)); + + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + verify(badgeService).saveEarned(eq(960), captor.capture()); + assertEquals("steady_syncer", captor.getValue().get(0).getBadgeId()); + } + + @Test + void getEarned_returnsListUnderEarned() throws Exception { + when(jwtUtil.extractUserId("tok")).thenReturn(960); + when(badgeService.getEarned(960)).thenReturn(List.of(new BadgeEarnedDTO("timely_reporter", 1, 5L))); + + mockMvc.perform(get("/badges/earned").header("JwtToken", "tok")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.earned[0].badgeId").value("timely_reporter")) + .andExpect(jsonPath("$.earned[0].level").value(1)); + } + + @Test + void invalidJwt_returns500WithErrorShape() throws Exception { + when(jwtUtil.extractUserId("bad")).thenThrow(new RuntimeException("Invalid JWT token.")); + + mockMvc.perform(get("/badges/earned").header("JwtToken", "bad")) + .andExpect(status().isInternalServerError()) + .andExpect(jsonPath("$.status").value("Error")); + } +} diff --git a/src/test/java/com/iemr/flw/service/BadgeServiceTest.java b/src/test/java/com/iemr/flw/service/BadgeServiceTest.java new file mode 100644 index 000000000..b1e7ac384 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/BadgeServiceTest.java @@ -0,0 +1,55 @@ +package com.iemr.flw.service; + +import com.iemr.flw.domain.iemr.BadgeEarned; +import com.iemr.flw.dto.iemr.BadgeEarnedDTO; +import com.iemr.flw.repo.iemr.BadgeConfigRepo; +import com.iemr.flw.repo.iemr.BadgeEarnedRepo; +import com.iemr.flw.repo.iemr.BadgeStreakFreezeRepo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class BadgeServiceTest { + + @Mock private BadgeConfigRepo configRepo; + @Mock private BadgeStreakFreezeRepo freezeRepo; + @Mock private BadgeEarnedRepo earnedRepo; + + private BadgeService service; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + service = new BadgeService(configRepo, freezeRepo, earnedRepo); + } + + @Test + void saveEarned_skipsRowsAlreadyKnown_idempotentReupload() { + when(earnedRepo.existsByUserIdAndBadgeIdAndLevel(960, "steady_syncer", 1)).thenReturn(true); + when(earnedRepo.existsByUserIdAndBadgeIdAndLevel(960, "steady_syncer", 2)).thenReturn(false); + + int inserted = service.saveEarned(960, List.of( + new BadgeEarnedDTO("steady_syncer", 1, 10L), + new BadgeEarnedDTO("steady_syncer", 2, 20L))); + + assertEquals(1, inserted); + verify(earnedRepo, times(1)).save(any(BadgeEarned.class)); + } + + @Test + void saveEarned_ignoresMalformedEntriesAndEmptyLists() { + assertEquals(0, service.saveEarned(960, null)); + assertEquals(0, service.saveEarned(960, List.of(new BadgeEarnedDTO(null, null, null)))); + verify(earnedRepo, never()).save(any()); + } +} From 8545e8e2608c6d627038f62f0326144786b33a1e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 7 Sep 2026 20:08:50 +0530 Subject: [PATCH 078/237] fix approval status issuse --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index b09de3f80..0c1f0ebb4 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -85,7 +85,7 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In .withDayOfMonth(5); boolean isOverDue = - rollName.equalsIgnoreCase("ANM") + (rollName.equalsIgnoreCase("ANM") || rollName.equalsIgnoreCase("ASHA Supervisor")) && today.isAfter(dueDate); @@ -757,9 +757,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else { countList = incentiveRecordRepo.getStatusCountByAshaIdOfDefaultActivity(ashaId, startDate, endDate); - countList = incentiveRecordRepo - .getStatusCountByAshaId( - ashaId, startDate, endDate); } logger.info("countList = {}", Arrays.deepToString(countList.toArray())); From 78dd30b691f9e8b4e8d2e58947bdff4237e8b052 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 7 Sep 2026 20:30:07 +0530 Subject: [PATCH 079/237] fix approval status issuse --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 0c1f0ebb4..d86974816 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -532,7 +532,6 @@ public String getSupervisorSubCenter(Integer supervisorUserID, Integer month, In if (verified > 0) overallVerified += 1; if (rejected > 0) overallRejected += 1; - if (pending > 0) overallPending += 1; if (pending > 0) { if (isOverDue) { From 20cc2dfbf8f39217001cca62a926fcd3bd4335fc Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 7 Sep 2026 20:37:58 +0530 Subject: [PATCH 080/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index d86974816..707b9b4de 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -838,10 +838,60 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .filter(r ->(r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104)) && r.getIsDefaultActivity() && !r.getIsClaimed()) .collect(Collectors.toList()); }else{ - incentiveActivityRecord = dbRecords.stream() - .filter(r ->( approvalStatusID == 0 || - approvalStatusID.equals(r.getApprovalStatus())) && r.getIsDefaultActivity() && isWithin24Hours(r.getCalimedDate())) - .collect(Collectors.toList()); + + if (isOverDue) { + + incentiveActivityRecord = dbRecords.stream() + .filter(r -> + Objects.equals(r.getApprovalStatus(), 105) + || Objects.equals(r.getApprovalStatus(), 102) + || Objects.equals(r.getApprovalStatus(), 104) + ) + .peek(r -> { + logger.info( + "Matched Record -> id: {}, original approvalStatus: {}", + r.getId(), + r.getApprovalStatus() + ); + + if (Objects.equals(r.getApprovalStatus(), 102) + || Objects.equals(r.getApprovalStatus(), 105)) { + + logger.info( + "Changing approvalStatus for record id: {} from {} to 104", + r.getId(), + r.getApprovalStatus() + ); + + r.setApprovalStatus(104); + } + }) + .collect(Collectors.toList()); + + logger.info("Filtered incentiveActivityRecord count: {}", + incentiveActivityRecord.size()); + + incentiveActivityRecord.forEach(r -> + logger.info( + "Final Record -> id: {}, approvalStatus: {}, ashaId: {}, benId: {}, activityId: {}", + r.getId(), + r.getApprovalStatus(), + r.getAshaId(), + r.getBenId(), + r.getActivityId() + ) + ); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); + }else { + incentiveActivityRecord = dbRecords.stream() + .filter(r ->( approvalStatusID == 0 || + approvalStatusID.equals(r.getApprovalStatus())) && r.getIsDefaultActivity()) + .collect(Collectors.toList()); + } } }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { @@ -1196,7 +1246,7 @@ public int updateApprovalStatus(Integer ashaId, if ("ASHA Supervisor".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())) { updatedCount = incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( - ashaId, approvalStatus, startDate, endDate, + ashaId, 105, startDate, endDate, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); @@ -1254,7 +1304,7 @@ public int updateApprovalStatus(Integer ashaId, Long id = Long.parseLong(incentiveId.trim()); - updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveId(id, ashaId, approvalStatus, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveId(id, ashaId, 105, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); } } From b0c66bb9013251657d897f44b62389b18938cd64 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 09:33:29 +0530 Subject: [PATCH 081/237] fix approval status issuse --- .../service/impl/SupervisorDashboardServiceImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 707b9b4de..76b1dfd2e 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1131,7 +1131,15 @@ && isAfter24Hours(r.getCalimedDate())) { if (totalAmount == null || totalAmount <= 0) continue; } - + logger.info( + "Incentive counts for ASHA ID {} - pending: {}, verified: {}, rejected: {}, unclaimedCount: {}, overallOverDue: {}", + ashaId, + pending, + verified, + rejected, + unclaimedCount, + overallOverDue + ); if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overallOverDue==0) continue; From 9864eabf650ec7ce2bb7c188ec6e151e2e19c618 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 09:45:55 +0530 Subject: [PATCH 082/237] fix approval status issuse --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 76b1dfd2e..0a48cee2d 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -886,6 +886,8 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .filter(Objects::nonNull) .mapToLong(Long::longValue) .sum(); + overallOverDue++; + }else { incentiveActivityRecord = dbRecords.stream() .filter(r ->( approvalStatusID == 0 || @@ -966,6 +968,7 @@ && isAfter24Hours(r.getCalimedDate())) { .filter(Objects::nonNull) .mapToLong(Long::longValue) .sum(); + overallOverDue++; } }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() From 5fcd5489bfea1c73c1d9f8cbf5bace7cd6bbc175 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 10:29:18 +0530 Subject: [PATCH 083/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 161 +++++------------- 1 file changed, 47 insertions(+), 114 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 0a48cee2d..20163c984 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -641,9 +641,9 @@ public String getSupervisorSubCenter(Integer supervisorUserID, Integer month, In - @Override - public Map getAshasAtFacility(Integer supervisorId, Integer facilityId, - Integer month, Integer year, Integer approvalStatusID) { + @Override + public Map getAshasAtFacility(Integer supervisorId, Integer facilityId, + Integer month, Integer year, Integer approvalStatusID) { Integer supervisorstateCode = userService.getUserDetail(supervisorId).getStateId(); List rows = null; LocalDate today = LocalDate.now(); @@ -727,8 +727,10 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci } logger.info("Other:" + rows); + long pending = 0, verified = 0, rejected = 0 , unclaimedCount = 0 , overDue = 0 ; - long overallVerified = 0, overallRejected = 0, overallPending = 0 , overallUnclaimed=0 ,overallOverDue =0; + + long overallVerified = 0, overallRejected = 0, overallPending = 0 , overallUnclaimed=0 ,overallOverDue =0; String facilityName = ""; String facilityType = ""; @@ -749,6 +751,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci List countList =null; if(supervisorstateCode.equals(StateCode.CG.getStateCode())){ + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ if(approvalStatusID.equals(106)){ countList = incentiveRecordRepo.getStatusUnclaimedCountByAshaId(ashaId, startDate, endDate); @@ -791,6 +794,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci totalAmount = incentiveRecordRepo.getTotalAmountByAsha( ashaId, startDate, endDate, approvalStatusID, stateCode); }else if(stateCode.equals(StateCode.CG.getStateCode())){ + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ totalAmount = incentiveRecordRepo.getDefaultActivityTotalAmountByAsha( ashaId, startDate, endDate, approvalStatusID, stateCode); @@ -819,7 +823,44 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if(stateCode.equals(StateCode.CG.getStateCode())){ List dbRecords = incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate); - if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + + if (approvalStatusID.equals(104) && isOverDue) { + + incentiveActivityRecord = dbRecords.stream() + .filter(record -> + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals(record.getApprovalStatus(), 105) + || Objects.equals(record.getApprovalStatus(), 104) + ) + .filter(record -> + !"ASHA Supervisor".equalsIgnoreCase(roleName) + || Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + ) + .peek(record -> { + logger.info( + "Overdue record matched: ashaId={}, recordId={}, " + + "oldStatus={}, claimedDate={}", + ashaId, + record.getId(), + record.getApprovalStatus(), + record.getCalimedDate() + ); + + record.setApprovalStatus(104); + }) + .collect(Collectors.toList()); + overDue = incentiveActivityRecord.size(); + + + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); + + } else if("ASHA Supervisor".equalsIgnoreCase(roleName)){ if(approvalStatusID.equals(105)){ incentiveActivityRecord = dbRecords.stream() .filter(r -> (r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(105)) && r.getIsDefaultActivity()) @@ -837,63 +878,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveActivityRecord = dbRecords.stream() .filter(r ->(r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104)) && r.getIsDefaultActivity() && !r.getIsClaimed()) .collect(Collectors.toList()); - }else{ - - if (isOverDue) { - - incentiveActivityRecord = dbRecords.stream() - .filter(r -> - Objects.equals(r.getApprovalStatus(), 105) - || Objects.equals(r.getApprovalStatus(), 102) - || Objects.equals(r.getApprovalStatus(), 104) - ) - .peek(r -> { - logger.info( - "Matched Record -> id: {}, original approvalStatus: {}", - r.getId(), - r.getApprovalStatus() - ); - - if (Objects.equals(r.getApprovalStatus(), 102) - || Objects.equals(r.getApprovalStatus(), 105)) { - - logger.info( - "Changing approvalStatus for record id: {} from {} to 104", - r.getId(), - r.getApprovalStatus() - ); - - r.setApprovalStatus(104); - } - }) - .collect(Collectors.toList()); - - logger.info("Filtered incentiveActivityRecord count: {}", - incentiveActivityRecord.size()); - - incentiveActivityRecord.forEach(r -> - logger.info( - "Final Record -> id: {}, approvalStatus: {}, ashaId: {}, benId: {}, activityId: {}", - r.getId(), - r.getApprovalStatus(), - r.getAshaId(), - r.getBenId(), - r.getActivityId() - ) - ); - totalAmount = incentiveActivityRecord.stream() - .map(IncentiveActivityRecord::getAmount) - .filter(Objects::nonNull) - .mapToLong(Long::longValue) - .sum(); - overallOverDue++; - - }else { - incentiveActivityRecord = dbRecords.stream() - .filter(r ->( approvalStatusID == 0 || - approvalStatusID.equals(r.getApprovalStatus())) && r.getIsDefaultActivity()) - .collect(Collectors.toList()); - } } }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { @@ -920,56 +904,6 @@ && isAfter24Hours(r.getCalimedDate())) { r.getActivityId() ) ); - - if (isOverDue) { - - incentiveActivityRecord = dbRecords.stream() - .filter(r -> - Objects.equals(r.getApprovalStatus(), 105) - || Objects.equals(r.getApprovalStatus(), 102) - || Objects.equals(r.getApprovalStatus(), 104) - ) - .peek(r -> { - logger.info( - "Matched Record -> id: {}, original approvalStatus: {}", - r.getId(), - r.getApprovalStatus() - ); - - if (Objects.equals(r.getApprovalStatus(), 102) - || Objects.equals(r.getApprovalStatus(), 105)) { - - logger.info( - "Changing approvalStatus for record id: {} from {} to 104", - r.getId(), - r.getApprovalStatus() - ); - - r.setApprovalStatus(104); - } - }) - .collect(Collectors.toList()); - - logger.info("Filtered incentiveActivityRecord count: {}", - incentiveActivityRecord.size()); - - incentiveActivityRecord.forEach(r -> - logger.info( - "Final Record -> id: {}, approvalStatus: {}, ashaId: {}, benId: {}, activityId: {}", - r.getId(), - r.getApprovalStatus(), - r.getAshaId(), - r.getBenId(), - r.getActivityId() - ) - ); - totalAmount = incentiveActivityRecord.stream() - .map(IncentiveActivityRecord::getAmount) - .filter(Objects::nonNull) - .mapToLong(Long::longValue) - .sum(); - overallOverDue++; - } }else if(approvalStatusID.equals(106)){ incentiveActivityRecord = dbRecords.stream() .filter(r->!r.getIsClaimed() && r.getApprovalStatus().equals(102)).peek(r->{r.setApprovalStatus(106);}).collect(Collectors.toList()); @@ -1053,7 +987,6 @@ && isAfter24Hours(r.getCalimedDate())) { - long pending = 0, verified = 0, rejected = 0 , unclaimedCount = 0 , overDue = 0 ; if (countList != null && !countList.isEmpty()) { @@ -1144,7 +1077,7 @@ && isAfter24Hours(r.getCalimedDate())) { overallOverDue ); - if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overallOverDue==0) continue; + if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overDue==0) continue; if (approvalStatusID.equals(0)) { asha.put("approvalStatus", approvalStatus); From bf7579773cb5d910946059c67448fd0021790acd Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 12:25:21 +0530 Subject: [PATCH 084/237] fix approval status issuse --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 20163c984..655cb0fc8 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -658,9 +658,10 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .plusMonths(1) .withDayOfMonth(5); - boolean isOverDue = - roleName.equalsIgnoreCase("ANM") - && today.isAfter(dueDate); + boolean isOverDue = + ("ANM".equalsIgnoreCase(roleName) + || "ASHA Supervisor".equalsIgnoreCase(roleName)) + && today.isAfter(dueDate); logger.info("Login user role:"+ roleName); From 8f6c7829eb97166a66de077ea9ee72e75b8134ff Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 12:32:33 +0530 Subject: [PATCH 085/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 655cb0fc8..189ebf2a7 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -244,7 +244,6 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In if (verified > 0) overallVerified += 1; if (rejected > 0) overallRejected += 1; - if (pending > 0) overallPending += 1; if (pending > 0) { if (isOverDue) { @@ -1064,8 +1063,17 @@ && isAfter24Hours(r.getCalimedDate())) { if (!activityList.isEmpty()) { approvalStatus = (int) activityList.get(0).get("approvalStatus"); } - if(!approvalStatusID.equals(106) || !facilityId.equals(0)){ - if (totalAmount == null || totalAmount <= 0) continue; + if (!approvalStatusID.equals(104) + && (!approvalStatusID.equals(106) || !facilityId.equals(0))) { + + if (totalAmount == null || totalAmount <= 0) { + logger.info( + "Skipping ASHA {} because totalAmount={}", + ashaId, + totalAmount + ); + continue; + } } logger.info( From d4fb60498526871280609d886baad1900c65a7bc Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 12:54:06 +0530 Subject: [PATCH 086/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 138 +++++++++++++++++- 1 file changed, 132 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 189ebf2a7..181e91d95 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -861,23 +861,149 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .sum(); } else if("ASHA Supervisor".equalsIgnoreCase(roleName)){ - if(approvalStatusID.equals(105)){ + if (approvalStatusID.equals(102)) { + incentiveActivityRecord = dbRecords.stream() - .filter(r -> (r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(105)) && r.getIsDefaultActivity()) + .filter(record -> + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals( + record.getApprovalStatus(), 105 + ) + ) + .filter(record -> + Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + ) + .peek(record -> { + logger.info( + "Supervisor record matched: ashaId={}, " + + "recordId={}, oldStatus={}, isOverDue={}, " + + "defaultActivity={}", + ashaId, + record.getId(), + record.getApprovalStatus(), + isOverDue, + record.getIsDefaultActivity() + ); + + if (isOverDue) { + // Response में overdue दिखाना है + record.setApprovalStatus(104); + } + }) .collect(Collectors.toList()); - }else if(approvalStatusID.equals(106)){ + + if (isOverDue) { + overDue = incentiveActivityRecord.size(); + } + + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); + + } else if (approvalStatusID.equals(104) && isOverDue) { + + /* + */ + incentiveActivityRecord = dbRecords.stream() + .filter(record -> + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals( + record.getApprovalStatus(), 104 + ) + || Objects.equals( + record.getApprovalStatus(), 105 + ) + ) + .filter(record -> + Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + ) + .peek(record -> + record.setApprovalStatus(104) + ) + .collect(Collectors.toList()); + + overDue = incentiveActivityRecord.size(); + + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); + + } else if (approvalStatusID.equals(105)) { + incentiveActivityRecord = dbRecords.stream() - .filter(r ->r.getApprovalStatus().equals(102) && r.getIsDefaultActivity() && !r.getIsClaimed()) + .filter(record -> + ( + Objects.equals( + record.getApprovalStatus(), 101 + ) + || Objects.equals( + record.getApprovalStatus(), 105 + ) + ) + && Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + ) .collect(Collectors.toList()); + + } else if (approvalStatusID.equals(106)) { + + incentiveActivityRecord = dbRecords.stream() + .filter(record -> + Objects.equals(record.getApprovalStatus(), 102) + && Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + && !Boolean.TRUE.equals( + record.getIsClaimed() + ) + ) + .collect(Collectors.toList()); + totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) .filter(Objects::nonNull) .mapToLong(Long::longValue) .sum(); - }else if(approvalStatusID.equals(0)){ + + } else if (approvalStatusID.equals(0)) { + incentiveActivityRecord = dbRecords.stream() - .filter(r ->(r.getApprovalStatus().equals(102) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104)) && r.getIsDefaultActivity() && !r.getIsClaimed()) + .filter(record -> + ( + Objects.equals( + record.getApprovalStatus(), 101 + ) + || Objects.equals( + record.getApprovalStatus(), 102 + ) + || Objects.equals( + record.getApprovalStatus(), 103 + ) + || Objects.equals( + record.getApprovalStatus(), 104 + ) + || Objects.equals( + record.getApprovalStatus(), 105 + ) + ) + && Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + ) .collect(Collectors.toList()); + + } else { + + incentiveActivityRecord = Collections.emptyList(); } }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { From d667ca8263391b3253d64e1022bd1d569ca4e68a Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 13:06:26 +0530 Subject: [PATCH 087/237] fix approval status issuse --- .../repo/iemr/AshaSupervisorLoginRepo.java | 104 ++++++++++++++---- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java index 3b52abe28..4904d6c49 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java @@ -55,36 +55,92 @@ List getAshasAtFacility( @Param("endDate") Timestamp endDate); - @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " - + "COALESCE(u.AgentID,'') AS agentID, " - + "COALESCE(u.EmergencyContactNo,'') AS mobile, " - + "COALESCE(g.GenderName,'') AS gender " - + "FROM asha_supervisor_mapping asm " - + "JOIN m_User u ON u.UserID = asm.ashaUserID " - + "AND u.Deleted = false " - + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " - + "JOIN incentive_activity_record iar " - + "ON iar.asha_id = asm.ashaUserID " - + "WHERE asm.supervisorUserID = :supervisorUserID " - + "AND asm.facilityID = :facilityID " - + "AND asm.deleted = false " - + "AND iar.is_claimed = true " - + "AND iar.start_date >= :startDate " - + "AND iar.end_date < :endDate " - + "AND (" - + " :approvalStatus = 0 " - + " OR (:approvalStatus = 105 AND iar.approval_status IN (101,105)) " - + " OR (:approvalStatus = 106 AND iar.approval_status = 102) " - + " OR (:approvalStatus NOT IN (105,106) AND iar.approval_status = :approvalStatus)" - + ")", +// @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " +// + "COALESCE(u.AgentID,'') AS agentID, " +// + "COALESCE(u.EmergencyContactNo,'') AS mobile, " +// + "COALESCE(g.GenderName,'') AS gender " +// + "FROM asha_supervisor_mapping asm " +// + "JOIN m_User u ON u.UserID = asm.ashaUserID " +// + "AND u.Deleted = false " +// + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " +// + "JOIN incentive_activity_record iar " +// + "ON iar.asha_id = asm.ashaUserID " +// + "WHERE asm.supervisorUserID = :supervisorUserID " +// + "AND asm.facilityID = :facilityID " +// + "AND asm.deleted = false " +// + "AND iar.is_claimed = true " +// + "AND iar.start_date >= :startDate " +// + "AND iar.end_date < :endDate " +// + "AND (" +// + " :approvalStatus = 0 " +// + " OR (:approvalStatus = 105 AND iar.approval_status IN (101,105)) " +// + " OR (:approvalStatus = 106 AND iar.approval_status = 102) " +// + " OR (:approvalStatus NOT IN (105,106) AND iar.approval_status = :approvalStatus)" +// + ")", +// nativeQuery = true) +// List getAshasAtFacilityCg( +// @Param("supervisorUserID") Integer supervisorUserID, +// @Param("facilityID") Integer facilityID, +// @Param("approvalStatus") Integer approvalStatus, +// @Param("startDate") Timestamp startDate, +// @Param("endDate") Timestamp endDate); + + + @Query(value = + "SELECT DISTINCT " + + "asm.ashaUserID, " + + "u.FirstName, " + + "u.LastName, " + + "COALESCE(u.AgentID, '') AS agentID, " + + "COALESCE(u.EmergencyContactNo, '') AS mobile, " + + "COALESCE(g.GenderName, '') AS gender " + + + "FROM asha_supervisor_mapping asm " + + + "JOIN m_User u " + + "ON u.UserID = asm.ashaUserID " + + "AND u.Deleted = false " + + + "LEFT JOIN m_gender g " + + "ON g.GenderID = u.GenderID " + + + "JOIN incentive_activity_record iar " + + "ON iar.asha_id = asm.ashaUserID " + + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.facilityID = :facilityID " + + "AND asm.deleted = false " + + "AND iar.is_default_activity = true " + + "AND iar.start_date >= :startDate " + + "AND iar.end_date < :endDate " + + + "AND (" + + " (:approvalStatus = 0) " + + + " OR (:approvalStatus = 104 " + + " AND iar.is_claimed = true " + + " AND iar.approval_status IN (102, 105)) " + + + " OR (:approvalStatus = 105 " + + " AND iar.is_claimed = true " + + " AND iar.approval_status IN (101, 105)) " + + + " OR (:approvalStatus = 106 " + + " AND iar.is_claimed = false " + + " AND iar.approval_status = 102) " + + + " OR (:approvalStatus NOT IN (104, 105, 106) " + + " AND iar.is_claimed = true " + + " AND iar.approval_status = :approvalStatus) " + + ")", nativeQuery = true) List getAshasAtFacilityCg( @Param("supervisorUserID") Integer supervisorUserID, @Param("facilityID") Integer facilityID, @Param("approvalStatus") Integer approvalStatus, @Param("startDate") Timestamp startDate, - @Param("endDate") Timestamp endDate); - + @Param("endDate") Timestamp endDate + ); @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + "COALESCE(u.AgentID,'') AS agentID, " From 60d48cebb2e21c7ab74f3b80b4dc3aa0b0c8cdf5 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 13:14:14 +0530 Subject: [PATCH 088/237] fix approval status issuse --- .../repo/iemr/AshaSupervisorLoginRepo.java | 74 ++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java index 4904d6c49..13b773717 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java @@ -142,36 +142,60 @@ List getAshasAtFacilityCg( @Param("endDate") Timestamp endDate ); - @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " - + "COALESCE(u.AgentID,'') AS agentID, " - + "COALESCE(u.EmergencyContactNo,'') AS mobile, " - + "COALESCE(g.GenderName,'') AS gender " - + "FROM asha_supervisor_mapping asm " - + "JOIN m_User u ON u.UserID = asm.ashaUserID " - + "AND u.Deleted = false " - + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " - + "JOIN incentive_activity_record iar " - + "ON iar.asha_id = asm.ashaUserID " - + "WHERE asm.supervisorUserID = :supervisorUserID " - + "AND asm.deleted = false " - + "AND (" - + " (:approvalStatus = 106 AND (iar.is_claimed = false OR iar.is_claimed IS NULL)) " - + " OR (:approvalStatus <> 106 AND iar.is_claimed = true)" - + ") " - + "AND iar.start_date >= :startDate " - + "AND iar.end_date < :endDate " - + "AND (" - + " :approvalStatus = 0 " - + " OR (:approvalStatus = 105 AND iar.approval_status IN (101,105)) " - + " OR (:approvalStatus = 106 AND iar.approval_status = 102) " - + " OR (:approvalStatus NOT IN (105,106) AND iar.approval_status = :approvalStatus)" - + ")", + @Query(value = + "SELECT DISTINCT " + + "asm.ashaUserID, " + + "u.FirstName, " + + "u.LastName, " + + "COALESCE(u.AgentID, '') AS agentID, " + + "COALESCE(u.EmergencyContactNo, '') AS mobile, " + + "COALESCE(g.GenderName, '') AS gender " + + + "FROM asha_supervisor_mapping asm " + + + "JOIN m_User u " + + "ON u.UserID = asm.ashaUserID " + + "AND u.Deleted = false " + + + "LEFT JOIN m_gender g " + + "ON g.GenderID = u.GenderID " + + + "JOIN incentive_activity_record iar " + + "ON iar.asha_id = asm.ashaUserID " + + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false " + + "AND iar.is_default_activity = true " + + "AND iar.start_date >= :startDate " + + "AND iar.end_date < :endDate " + + + "AND (" + + " (:approvalStatus = 0) " + + + // Overdue: database status 102 or 105 + " OR (:approvalStatus = 104 " + + " AND iar.is_claimed = true " + + " AND iar.approval_status IN (102, 105)) " + + + " OR (:approvalStatus = 105 " + + " AND iar.is_claimed = true " + + " AND iar.approval_status IN (101, 105)) " + + + " OR (:approvalStatus = 106 " + + " AND iar.is_claimed = false " + + " AND iar.approval_status = 102) " + + + " OR (:approvalStatus NOT IN (104, 105, 106) " + + " AND iar.is_claimed = true " + + " AND iar.approval_status = :approvalStatus) " + + ")", nativeQuery = true) List getAshasAtFacilityCg( @Param("supervisorUserID") Integer supervisorUserID, @Param("approvalStatus") Integer approvalStatus, @Param("startDate") Timestamp startDate, - @Param("endDate") Timestamp endDate); + @Param("endDate") Timestamp endDate + ); From 6a0769b72058735834f53cb64b5de35ba42b5568 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 13:51:25 +0530 Subject: [PATCH 089/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 181e91d95..f9cc67e2e 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1009,14 +1009,37 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { if (approvalStatusID.equals(102)) { incentiveActivityRecord = dbRecords.stream() - .filter(r -> - r.getApprovalStatus().equals(105) - || (r.getApprovalStatus().equals(102))) - .peek(r -> { - if (r.getApprovalStatus().equals(102) - && isAfter24Hours(r.getCalimedDate())) { - r.setApprovalStatus(105); + .peek(record -> { + if (Objects.equals(record.getApprovalStatus(), 102)) { + record.setApprovalStatus(105); + } + }) + .filter(record -> { + boolean validStatus = + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals( + record.getApprovalStatus(), 105 + ); + + if (!validStatus) { + return false; } + + boolean isDefaultActivity = + Boolean.TRUE.equals( + record.getIsDefaultActivity() + ); + + boolean isApproved = + Boolean.TRUE.equals(record.getIsApproved()); + + if (!isDefaultActivity) { + return true; + } + + + return Objects.equals(record.getApprovalStatus(), 105) + || isApproved; }) .collect(Collectors.toList()); From ffa470e6365bf8d40951c6fa4f015ea053fc0c7b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 14:03:25 +0530 Subject: [PATCH 090/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index f9cc67e2e..bb7c14990 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1010,38 +1010,26 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if (approvalStatusID.equals(102)) { incentiveActivityRecord = dbRecords.stream() .peek(record -> { - if (Objects.equals(record.getApprovalStatus(), 102)) { + if (Objects.equals(record.getApprovalStatus(), 102) + && isAfter24Hours(record.getCalimedDate())) { record.setApprovalStatus(105); } }) - .filter(record -> { - boolean validStatus = - Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals( - record.getApprovalStatus(), 105 - ); - - if (!validStatus) { - return false; - } - - boolean isDefaultActivity = - Boolean.TRUE.equals( - record.getIsDefaultActivity() - ); - - boolean isApproved = - Boolean.TRUE.equals(record.getIsApproved()); - - if (!isDefaultActivity) { - return true; - } - - - return Objects.equals(record.getApprovalStatus(), 105) - || isApproved; - }) + .filter(record -> + Boolean.TRUE.equals(record.getIsDefaultActivity()) + && ( + Objects.equals(record.getApprovalStatus(), 105) + || Boolean.TRUE.equals( + record.getIsApproved() + ) + ) + ) .collect(Collectors.toList()); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); dbRecords.forEach(r -> logger.info( From 3542c54d3d583f6af8d2454691c3d38104776f50 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 14:04:57 +0530 Subject: [PATCH 091/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index bb7c14990..0bd8796ba 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1016,11 +1016,19 @@ && isAfter24Hours(record.getCalimedDate())) { } }) .filter(record -> - Boolean.TRUE.equals(record.getIsDefaultActivity()) - && ( - Objects.equals(record.getApprovalStatus(), 105) - || Boolean.TRUE.equals( - record.getIsApproved() + // Non-default activity always show + !Boolean.TRUE.equals(record.getIsDefaultActivity()) + + // Default activity condition + || ( + Boolean.TRUE.equals(record.getIsDefaultActivity()) + && ( + Objects.equals( + record.getApprovalStatus(), 105 + ) + || Boolean.TRUE.equals( + record.getIsApproved() + ) ) ) ) From 10b2f1efd7dc840eb430cf4c7098efc60a0a1893 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 14:19:26 +0530 Subject: [PATCH 092/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 0bd8796ba..b63f4b555 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1009,29 +1009,26 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { if (approvalStatusID.equals(102)) { incentiveActivityRecord = dbRecords.stream() + .filter(record -> + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals(record.getApprovalStatus(), 105) + ) .peek(record -> { if (Objects.equals(record.getApprovalStatus(), 102) - && isAfter24Hours(record.getCalimedDate())) { + && Boolean.TRUE.equals(record.getIsDefaultActivity()) + && Boolean.TRUE.equals(record.getIsApproved())) { + + logger.info( + "Changing status 102 to 105: recordId={}, " + + "isDefaultActivity={}, isApproved={}", + record.getId(), + record.getIsDefaultActivity(), + record.getIsApproved() + ); + record.setApprovalStatus(105); } }) - .filter(record -> - // Non-default activity always show - !Boolean.TRUE.equals(record.getIsDefaultActivity()) - - // Default activity condition - || ( - Boolean.TRUE.equals(record.getIsDefaultActivity()) - && ( - Objects.equals( - record.getApprovalStatus(), 105 - ) - || Boolean.TRUE.equals( - record.getIsApproved() - ) - ) - ) - ) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) From 24fe99ea96a3c81d4edab8ec0b6c01c6bf3fbb5f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 14:28:17 +0530 Subject: [PATCH 093/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index b63f4b555..792fc64b2 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1013,22 +1013,23 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci Objects.equals(record.getApprovalStatus(), 102) || Objects.equals(record.getApprovalStatus(), 105) ) + .peek(record -> { if (Objects.equals(record.getApprovalStatus(), 102) && Boolean.TRUE.equals(record.getIsDefaultActivity()) && Boolean.TRUE.equals(record.getIsApproved())) { - logger.info( - "Changing status 102 to 105: recordId={}, " + - "isDefaultActivity={}, isApproved={}", - record.getId(), - record.getIsDefaultActivity(), - record.getIsApproved() - ); - record.setApprovalStatus(105); } }) + + .filter(record -> + !Boolean.TRUE.equals(record.getIsDefaultActivity()) + || ( + Objects.equals(record.getApprovalStatus(), 105) + && Boolean.TRUE.equals(record.getIsApproved()) + ) + ) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) From f58efb2182502196f7ac97c843e15f3712aa0d52 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 14:35:03 +0530 Subject: [PATCH 094/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 81 ++++++++++++++----- 1 file changed, 62 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 792fc64b2..8abcc26dc 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1008,29 +1008,72 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { if (approvalStatusID.equals(102)) { - incentiveActivityRecord = dbRecords.stream() - .filter(record -> - Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals(record.getApprovalStatus(), 105) - ) + if (Objects.equals(approvalStatusID, 102)) { - .peek(record -> { - if (Objects.equals(record.getApprovalStatus(), 102) - && Boolean.TRUE.equals(record.getIsDefaultActivity()) - && Boolean.TRUE.equals(record.getIsApproved())) { + incentiveActivityRecord = dbRecords.stream() - record.setApprovalStatus(105); - } - }) + .filter(record -> + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals( + record.getApprovalStatus(), 105 + ) + ) - .filter(record -> - !Boolean.TRUE.equals(record.getIsDefaultActivity()) - || ( - Objects.equals(record.getApprovalStatus(), 105) - && Boolean.TRUE.equals(record.getIsApproved()) + .peek(record -> { + if (Objects.equals(record.getApprovalStatus(), 102) + && Boolean.TRUE.equals( + record.getIsDefaultActivity() ) - ) - .collect(Collectors.toList()); + && Boolean.TRUE.equals( + record.getIsApproved() + )) { + + logger.info( + "Changing record status 102 to 105: " + + "id={}, activityId={}", + record.getId(), + record.getActivityId() + ); + + record.setApprovalStatus(105); + } + }) + + + .filter(record -> + !Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + || Boolean.TRUE.equals( + record.getIsApproved() + ) + ) + .collect(Collectors.toList()); + + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); + + logger.info( + "ANM final filtered records: count={}, totalAmount={}", + incentiveActivityRecord.size(), + totalAmount + ); + + incentiveActivityRecord.forEach(record -> + logger.info( + "Final record: id={}, activityId={}, status={}, " + + "default={}, approved={}", + record.getId(), + record.getActivityId(), + record.getApprovalStatus(), + record.getIsDefaultActivity(), + record.getIsApproved() + ) + ); + } totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) .filter(Objects::nonNull) From 9a807faedd6cbe4b30d166211c6079d316ca1808 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 14:45:15 +0530 Subject: [PATCH 095/237] fix approval status issuse --- .../service/impl/IncentiveServiceImpl.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 8d3ee8f42..60bba5239 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -545,13 +545,25 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) .collect(Collectors.toList()); }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - records = records.stream() - .filter(r -> - validActivityIds.contains(r.getActivityId()) - ) - .collect(Collectors.toList()); - } + records = records.stream() + .filter(record -> + validActivityIds.contains(record.getActivityId()) + ) + .filter(record -> + !Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + + || Boolean.TRUE.equals( + record.getIsApproved() + ) + ) + .collect(Collectors.toList()); + + logger.info( + "ANM/CHO records after default activity filter: {}", + records.size() + ); } }else { From 1930a7018a1656ac0812c43e8798190194ddf36c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 15:02:18 +0530 Subject: [PATCH 096/237] fix approval status issuse --- .../impl/SupervisorDashboardServiceImpl.java | 60 +++++++++++++++---- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 8abcc26dc..4bbc79018 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -824,35 +824,65 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci List dbRecords = incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate); - if (approvalStatusID.equals(104) && isOverDue) { + if (Objects.equals(approvalStatusID, 104) && isOverDue) { incentiveActivityRecord = dbRecords.stream() + + // Overdue applicable statuses .filter(record -> Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals(record.getApprovalStatus(), 105) || Objects.equals(record.getApprovalStatus(), 104) + || Objects.equals(record.getApprovalStatus(), 105) ) - .filter(record -> - !"ASHA Supervisor".equalsIgnoreCase(roleName) - || Boolean.TRUE.equals( - record.getIsDefaultActivity() - ) - ) + + // Role-wise activity filtering + .filter(record -> { + + boolean isDefault = + Boolean.TRUE.equals( + record.getIsDefaultActivity() + ); + + boolean isApproved = + Boolean.TRUE.equals( + record.getIsApproved() + ); + + if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { + // Supervisor: only approved default activities + return isDefault && isApproved; + } + + if ("ANM".equalsIgnoreCase(roleName) + || "CHO".equalsIgnoreCase(roleName)) { + // ANM/CHO: + // all non-default activities + // default activity only when approved + return !isDefault || isApproved; + } + + return false; + }) + .peek(record -> { logger.info( - "Overdue record matched: ashaId={}, recordId={}, " + - "oldStatus={}, claimedDate={}", + "Overdue record matched: role={}, ashaId={}, " + + "recordId={}, oldStatus={}, default={}, " + + "approved={}, claimedDate={}", + roleName, ashaId, record.getId(), record.getApprovalStatus(), + record.getIsDefaultActivity(), + record.getIsApproved(), record.getCalimedDate() ); record.setApprovalStatus(104); }) .collect(Collectors.toList()); - overDue = incentiveActivityRecord.size(); + overDue = incentiveActivityRecord.size(); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) @@ -860,6 +890,13 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .mapToLong(Long::longValue) .sum(); + logger.info( + "Overdue final: role={}, ashaId={}, count={}, totalAmount={}", + roleName, + ashaId, + overDue, + totalAmount + ); } else if("ASHA Supervisor".equalsIgnoreCase(roleName)){ if (approvalStatusID.equals(102)) { @@ -888,7 +925,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci ); if (isOverDue) { - // Response में overdue दिखाना है record.setApprovalStatus(104); } }) From 269736d464b0dd107038ee9b68d2394183e0b3e6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 8 Sep 2026 15:28:52 +0530 Subject: [PATCH 097/237] fix issue of default activity approval status --- .../flw/service/impl/IncentiveServiceImpl.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 60bba5239..c2440ee2e 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -1023,15 +1023,15 @@ private void checkMonthlyAshaIncentive(Integer ashaId) { IncentiveActivity ADDITIONAL_ASHA_INCENTIVE = incentivesRepo.findIncentiveMasterByNameAndGroup("ADDITIONAL_ASHA_INCENTIVE", GroupName.ADDITIONAL_INCENTIVE.getDisplayName()); IncentiveActivity ASHA_MONTHLY_ROUTINE = incentivesRepo.findIncentiveMasterByNameAndGroup("ASHA_MONTHLY_ROUTINE", GroupName.ASHA_MONTHLY_ROUTINE.getDisplayName()); if (MOBILEBILLREIMB_ACTIVITY != null) { - addMonthlyAshaIncentiveRecord(MOBILEBILLREIMB_ACTIVITY, ashaId, userName); + addMonthlyAshaIncentiveRecord(MOBILEBILLREIMB_ACTIVITY, ashaId, userName,false); } if (ADDITIONAL_ASHA_INCENTIVE != null) { - addMonthlyAshaIncentiveRecord(ADDITIONAL_ASHA_INCENTIVE, ashaId, userName); + addMonthlyAshaIncentiveRecord(ADDITIONAL_ASHA_INCENTIVE, ashaId, userName,false); } if (ASHA_MONTHLY_ROUTINE != null) { - addMonthlyAshaIncentiveRecord(ASHA_MONTHLY_ROUTINE, ashaId, userName); + addMonthlyAshaIncentiveRecord(ASHA_MONTHLY_ROUTINE, ashaId, userName,false); } } catch (Exception e) { @@ -1049,15 +1049,15 @@ private void checkMonthlyAshaIncentiveForCg(Integer ashaId) { IncentiveActivity MITANIN_REGISTER_5_INFO_FILL = incentivesRepo.findIncentiveMasterByNameAndGroup("MITANIN_REGISTER_5_INFO_FILL", GroupName.ACTIVITY.getDisplayName()); IncentiveActivity MITANIN_REGISTER = incentivesRepo.findIncentiveMasterByNameAndGroup("MITANIN_REGISTER", GroupName.ACTIVITY.getDisplayName()); if (MONTHLY_HONORARIUM != null) { - addMonthlyAshaIncentiveRecord(MONTHLY_HONORARIUM, ashaId, userName); + addMonthlyAshaIncentiveRecord(MONTHLY_HONORARIUM, ashaId, userName,true); } if (MITANIN_REGISTER_5_INFO_FILL != null) { - addMonthlyAshaIncentiveRecord(MITANIN_REGISTER_5_INFO_FILL, ashaId, userName); + addMonthlyAshaIncentiveRecord(MITANIN_REGISTER_5_INFO_FILL, ashaId, userName,false); } if (MITANIN_REGISTER != null) { - addMonthlyAshaIncentiveRecord(MITANIN_REGISTER, ashaId, userName); + addMonthlyAshaIncentiveRecord(MITANIN_REGISTER, ashaId, userName,false); } } catch (Exception e) { @@ -1067,7 +1067,7 @@ private void checkMonthlyAshaIncentiveForCg(Integer ashaId) { } - private void addMonthlyAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId, String userName) { + private void addMonthlyAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId, String userName,Boolean isApproved) { try { Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); @@ -1096,6 +1096,7 @@ record = new IncentiveActivityRecord(); record.setAshaId(ashaId); record.setIsEligible(true); record.setIsDefaultActivity(true); + record.setIsApproved(isApproved); record.setAmount(Long.valueOf(incentiveActivity.getRate())); recordRepo.save(record); } From 4612619e1c683fb3be7bfeb8a3a05df0dbb0ad93 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 08:50:50 +0530 Subject: [PATCH 098/237] fix issue of default activity approval status --- .../repo/iemr/SupervisorDashboardRepo.java | 21 ++- .../impl/SupervisorDashboardServiceImpl.java | 169 ++++++++++++++---- 2 files changed, 153 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java index 071aeab0e..fab2b4654 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -66,19 +66,38 @@ public interface SupervisorDashboardRepo extends JpaRepository= :startDate " + + "AND iar.created_date < :endDate " + + "AND iar.approval_status = 102 " + + "AND iar.is_default_activity = true " + + "AND (iar.is_claimed = false OR iar.is_claimed IS NULL) " + + "GROUP BY iar.asha_id", + nativeQuery = true) + List getDefaultUnclaimedCountByAshaIds( + @Param("ashaIds") List ashaIds, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate + ); @Query(value = "SELECT iar.asha_id, " + "COUNT(*) AS unclaimedCount " + "FROM incentive_activity_record iar " + "WHERE iar.asha_id IN (:ashaIds) " + "AND iar.created_date >= :startDate " + "AND iar.created_date < :endDate " + + "AND iar.approval_status = 102 " + "AND (iar.is_claimed = false OR iar.is_claimed IS NULL) " + "GROUP BY iar.asha_id", nativeQuery = true) List getUnclaimedCountByAshaIds( @Param("ashaIds") List ashaIds, @Param("startDate") Timestamp startDate, - @Param("endDate") Timestamp endDate); + @Param("endDate") Timestamp endDate + ); @Query(value = "SELECT COUNT(*) " + diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 4bbc79018..2491c96be 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -232,59 +232,156 @@ public String getSupervisorDashboard(Integer supervisorUserID, Integer month, In if (count > 0) overallUnclaimed += 1; } } - }else if(stateId.equals(StateCode.CG.getStateCode())){ - if("ASHA Supervisor".equalsIgnoreCase(rollName)){ - List statusRows = dashboardRepo.getDefaultIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); - if (statusRows != null) { - for (Object[] sRow : statusRows) { - long verified = ((Number) sRow[5]).longValue(); - long rejected = ((Number) sRow[3]).longValue(); - long pending = ((Number) sRow[4]).longValue(); + }else if (stateId.equals(StateCode.CG.getStateCode())) { + if ("ASHA Supervisor".equalsIgnoreCase(rollName)) { - if (verified > 0) overallVerified += 1; - if (rejected > 0) overallRejected += 1; + List statusRows = + dashboardRepo.getDefaultIncentiveStatusByAshaIds( + ashaIDs, + startDate, + endDate + ); - if (pending > 0) { - if (isOverDue) { - overallOverDue++; - } else { - overallPending++; - } + if (statusRows != null) { + for (Object[] statusRow : statusRows) { + + long verified = statusRow[5] != null + ? ((Number) statusRow[5]).longValue() + : 0L; + + long rejected = statusRow[3] != null + ? ((Number) statusRow[3]).longValue() + : 0L; + + long pending = statusRow[4] != null + ? ((Number) statusRow[4]).longValue() + : 0L; + + if (verified > 0) { + overallVerified++; + } + + if (rejected > 0) { + overallRejected++; + } + + if (pending > 0) { + if (isOverDue) { + overallOverDue++; + } else { + overallPending++; } + } + } + } + // ASHA Supervisor: only default unclaimed activities + List unclaimedRows = + dashboardRepo.getDefaultUnclaimedCountByAshaIds( + ashaIDs, + startDate, + endDate + ); + + if (unclaimedRows != null) { + for (Object[] unclaimedRow : unclaimedRows) { + + Integer ashaId = unclaimedRow[0] != null + ? ((Number) unclaimedRow[0]).intValue() + : null; + + long unclaimedCount = unclaimedRow[1] != null + ? ((Number) unclaimedRow[1]).longValue() + : 0L; + + logger.info( + "Supervisor unclaimed count: ashaId={}, count={}", + ashaId, + unclaimedCount + ); + + if (unclaimedCount > 0) { + overallUnclaimed++; } } - }else if("ANM".equalsIgnoreCase(rollName)){ - List statusRows = dashboardRepo.getIncentiveStatusByAshaIdsForAnm(ashaIDs, startDate, endDate); - if (statusRows != null) { - for (Object[] sRow : statusRows) { - long verified = ((Number) sRow[2]).longValue(); - long rejected = ((Number) sRow[3]).longValue(); - long pending = ((Number) sRow[5]).longValue(); + } - if (verified > 0) overallVerified += 1; - if (rejected > 0) overallRejected += 1; - if (pending > 0) { - if (isOverDue) { - overallOverDue++; - } else { - overallPending++; - } - } + } else if ("ANM".equalsIgnoreCase(rollName) + || "CHO".equalsIgnoreCase(rollName)) { + + List statusRows = + dashboardRepo.getIncentiveStatusByAshaIdsForAnm( + ashaIDs, + startDate, + endDate + ); + + if (statusRows != null) { + for (Object[] statusRow : statusRows) { + + long verified = statusRow[2] != null + ? ((Number) statusRow[2]).longValue() + : 0L; + long rejected = statusRow[3] != null + ? ((Number) statusRow[3]).longValue() + : 0L; + + long pending = statusRow[5] != null + ? ((Number) statusRow[5]).longValue() + : 0L; + + if (verified > 0) { + overallVerified++; + } + + if (rejected > 0) { + overallRejected++; + } + + if (pending > 0) { + if (isOverDue) { + overallOverDue++; + } else { + overallPending++; + } } } } - List unclaimedRows = dashboardRepo.getUnclaimedCountByAshaIds(ashaIDs, startDate, endDate); + // ANM/CHO: all unclaimed activities + List unclaimedRows = + dashboardRepo.getUnclaimedCountByAshaIds( + ashaIDs, + startDate, + endDate + ); + if (unclaimedRows != null) { - for (Object[] uRow : unclaimedRows) { - long count = ((Number) uRow[1]).longValue(); - if (count > 0) overallUnclaimed += 1; + for (Object[] unclaimedRow : unclaimedRows) { + + Integer ashaId = unclaimedRow[0] != null + ? ((Number) unclaimedRow[0]).intValue() + : null; + + long unclaimedCount = unclaimedRow[1] != null + ? ((Number) unclaimedRow[1]).longValue() + : 0L; + + logger.info( + "ANM/CHO unclaimed count: ashaId={}, count={}", + ashaId, + unclaimedCount + ); + + if (unclaimedCount > 0) { + overallUnclaimed++; + } } } } + } } catch (Exception e) { From 4ad7212c44c1c3b3f578a65168f1158250268b75 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 14:39:20 +0530 Subject: [PATCH 099/237] fix issue of default activity approval status --- .../impl/SupervisorDashboardServiceImpl.java | 53 +++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 2491c96be..c9dcd1a8c 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1037,6 +1037,23 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .mapToLong(Long::longValue) .sum(); + }else if (approvalStatusID.equals(103)) { + + incentiveActivityRecord = dbRecords.stream() + .filter(record -> + Objects.equals(record.getApprovalStatus(), 103) + && !Boolean.TRUE.equals( + record.getIsClaimed() + ) + ) + .collect(Collectors.toList()); + + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); + } else if (approvalStatusID.equals(104) && isOverDue) { /* @@ -1107,6 +1124,23 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .mapToLong(Long::longValue) .sum(); + }else if (approvalStatusID.equals(103)) { + + incentiveActivityRecord = dbRecords.stream() + .filter(record -> + Objects.equals(record.getApprovalStatus(), 103) + && !Boolean.TRUE.equals( + record.getIsClaimed() + ) + ) + .collect(Collectors.toList()); + + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); + } else if (approvalStatusID.equals(0)) { incentiveActivityRecord = dbRecords.stream() @@ -1252,8 +1286,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci return true; }) .peek(r -> { - if (r.getApprovalStatus().equals(102) - && isAfter24Hours(r.getCalimedDate())) { + if (r.getApprovalStatus().equals(102)) { r.setApprovalStatus(105); } }) @@ -1385,12 +1418,24 @@ && isAfter24Hours(r.getCalimedDate())) { if (!approvalStatusID.equals(104) && (!approvalStatusID.equals(106) || !facilityId.equals(0))) { - if (totalAmount == null || totalAmount <= 0) { + // Do not show the ASHA card when there are no activities +// or the total incentive amount is zero + if (incentiveActivityRecord == null + || incentiveActivityRecord.isEmpty() + || totalAmount == null + || totalAmount <= 0) { + logger.info( - "Skipping ASHA {} because totalAmount={}", + "Skipping ASHA card: ashaId={}, status={}, " + + "activityCount={}, totalAmount={}", ashaId, + approvalStatusID, + incentiveActivityRecord == null + ? 0 + : incentiveActivityRecord.size(), totalAmount ); + continue; } } From 922661159b9109d2251014f440ea529f87e1e29c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 14:48:54 +0530 Subject: [PATCH 100/237] fix issue of default activity approval status --- .../impl/SupervisorDashboardServiceImpl.java | 62 +++++++++---------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index c9dcd1a8c..832bf617e 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1078,7 +1078,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci ) .collect(Collectors.toList()); - overDue = incentiveActivityRecord.size(); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) @@ -1415,42 +1414,39 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if (!activityList.isEmpty()) { approvalStatus = (int) activityList.get(0).get("approvalStatus"); } - if (!approvalStatusID.equals(104) - && (!approvalStatusID.equals(106) || !facilityId.equals(0))) { - - // Do not show the ASHA card when there are no activities -// or the total incentive amount is zero - if (incentiveActivityRecord == null - || incentiveActivityRecord.isEmpty() - || totalAmount == null - || totalAmount <= 0) { - - logger.info( - "Skipping ASHA card: ashaId={}, status={}, " + - "activityCount={}, totalAmount={}", - ashaId, - approvalStatusID, - incentiveActivityRecord == null - ? 0 - : incentiveActivityRecord.size(), - totalAmount - ); - - continue; - } - } - logger.info( - "Incentive counts for ASHA ID {} - pending: {}, verified: {}, rejected: {}, unclaimedCount: {}, overallOverDue: {}", + "Card validation: ashaId={}, status={}, activityCount={}, totalAmount={}", ashaId, - pending, - verified, - rejected, - unclaimedCount, - overallOverDue + approvalStatusID, + incentiveActivityRecord == null + ? 0 + : incentiveActivityRecord.size(), + totalAmount ); - if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overDue==0) continue; +// Do not return a card when there are no matching activities +// or the total amount is zero + if (incentiveActivityRecord == null + || incentiveActivityRecord.isEmpty() + || totalAmount == null + || totalAmount <= 0) { + + logger.info( + "Skipping ASHA card: ashaId={}, activityCount={}, totalAmount={}", + ashaId, + incentiveActivityRecord == null + ? 0 + : incentiveActivityRecord.size(), + totalAmount + ); + + continue; + } + + + ashaList.add(asha); + + if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overallOverDue==0) continue; if (approvalStatusID.equals(0)) { asha.put("approvalStatus", approvalStatus); From 9a820b00bb817f8fdf0f37568ff87f69c9add486 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 14:54:49 +0530 Subject: [PATCH 101/237] fix issue of default activity approval status --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 832bf617e..4bd7b7fb8 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1446,7 +1446,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci ashaList.add(asha); - if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overallOverDue==0) continue; + if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overDue==0) continue; if (approvalStatusID.equals(0)) { asha.put("approvalStatus", approvalStatus); From 0a7911399eab9ef5900861f6ad18dea6632faf4d Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 14:55:12 +0530 Subject: [PATCH 102/237] fix issue of default activity approval status --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 4bd7b7fb8..f5a0e7944 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1078,6 +1078,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci ) .collect(Collectors.toList()); + overDue = incentiveActivityRecord.size(); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) From 86380f9495f1bf88bd9922b920f27f6a66e32758 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 15:02:33 +0530 Subject: [PATCH 103/237] fix issue of default activity approval status --- .../impl/SupervisorDashboardServiceImpl.java | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index f5a0e7944..00005f352 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1415,38 +1415,29 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if (!activityList.isEmpty()) { approvalStatus = (int) activityList.get(0).get("approvalStatus"); } + if (!approvalStatusID.equals(104) + && (!approvalStatusID.equals(106) || !facilityId.equals(0))) { + + if (totalAmount == null || totalAmount < 0) { + logger.info( + "Skipping ASHA {} because totalAmount={}", + ashaId, + totalAmount + ); + continue; + } + } + logger.info( - "Card validation: ashaId={}, status={}, activityCount={}, totalAmount={}", + "Incentive counts for ASHA ID {} - pending: {}, verified: {}, rejected: {}, unclaimedCount: {}, overallOverDue: {}", ashaId, - approvalStatusID, - incentiveActivityRecord == null - ? 0 - : incentiveActivityRecord.size(), - totalAmount + pending, + verified, + rejected, + unclaimedCount, + overallOverDue ); -// Do not return a card when there are no matching activities -// or the total amount is zero - if (incentiveActivityRecord == null - || incentiveActivityRecord.isEmpty() - || totalAmount == null - || totalAmount <= 0) { - - logger.info( - "Skipping ASHA card: ashaId={}, activityCount={}, totalAmount={}", - ashaId, - incentiveActivityRecord == null - ? 0 - : incentiveActivityRecord.size(), - totalAmount - ); - - continue; - } - - - ashaList.add(asha); - if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overDue==0) continue; if (approvalStatusID.equals(0)) { From 5674f54f2480380423d9c75a92926fc77e22df5b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 15:11:31 +0530 Subject: [PATCH 104/237] fix issue of default activity approval status --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 00005f352..d5967bfe3 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1415,10 +1415,9 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if (!activityList.isEmpty()) { approvalStatus = (int) activityList.get(0).get("approvalStatus"); } - if (!approvalStatusID.equals(104) - && (!approvalStatusID.equals(106) || !facilityId.equals(0))) { + if ((!approvalStatusID.equals(106) || !facilityId.equals(0))) { - if (totalAmount == null || totalAmount < 0) { + if (totalAmount == null || totalAmount <= 0) { logger.info( "Skipping ASHA {} because totalAmount={}", ashaId, From d02b80e0cfa80b5fc71515a951b81156b61ce4bc Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 15:14:23 +0530 Subject: [PATCH 105/237] fix issue of default activity approval status --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index d5967bfe3..83ab7128b 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1428,13 +1428,13 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci } logger.info( - "Incentive counts for ASHA ID {} - pending: {}, verified: {}, rejected: {}, unclaimedCount: {}, overallOverDue: {}", + "Incentive counts for ASHA ID {} - pending: {}, verified: {}, rejected: {}, unclaimedCount: {}, overallOverDue: {} , approvalStatus: {}", ashaId, pending, verified, rejected, unclaimedCount, - overallOverDue + overallOverDue,approvalStatus ); if (pending == 0 && verified == 0 && rejected == 0 && unclaimedCount == 0 && overDue==0) continue; From b375bb425e8ded2dfe6272c2a322c27b33c76331 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 15:27:19 +0530 Subject: [PATCH 106/237] fix issue of default activity approval status --- .../impl/SupervisorDashboardServiceImpl.java | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 83ab7128b..76859a8cb 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1039,14 +1039,23 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if (approvalStatusID.equals(103)) { - incentiveActivityRecord = dbRecords.stream() - .filter(record -> - Objects.equals(record.getApprovalStatus(), 103) - && !Boolean.TRUE.equals( - record.getIsClaimed() - ) - ) - .collect(Collectors.toList()); + if (Objects.equals(approvalStatusID, 103)) { + + // ASHA Supervisor can view only rejected default activities + // that are unclaimed + incentiveActivityRecord = dbRecords.stream() + .filter(record -> + Objects.equals(record.getApprovalStatus(), 103) + && !Boolean.TRUE.equals( + record.getIsClaimed() + ) + && Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + ) + .collect(Collectors.toList()); + } + totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) @@ -1124,24 +1133,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .mapToLong(Long::longValue) .sum(); - }else if (approvalStatusID.equals(103)) { - - incentiveActivityRecord = dbRecords.stream() - .filter(record -> - Objects.equals(record.getApprovalStatus(), 103) - && !Boolean.TRUE.equals( - record.getIsClaimed() - ) - ) - .collect(Collectors.toList()); - - totalAmount = incentiveActivityRecord.stream() - .map(IncentiveActivityRecord::getAmount) - .filter(Objects::nonNull) - .mapToLong(Long::longValue) - .sum(); - - } else if (approvalStatusID.equals(0)) { + }else if (approvalStatusID.equals(0)) { incentiveActivityRecord = dbRecords.stream() .filter(record -> @@ -1268,6 +1260,18 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }else if(approvalStatusID.equals(0)){ incentiveActivityRecord = dbRecords.stream() .filter(r->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed()) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104))).collect(Collectors.toList()); + }if (Objects.equals(approvalStatusID, 103)) { + + // ANM/CHO can view all rejected activities + // that are unclaimed + incentiveActivityRecord = dbRecords.stream() + .filter(record -> + Objects.equals(record.getApprovalStatus(), 103) + && !Boolean.TRUE.equals( + record.getIsClaimed() + ) + ) + .collect(Collectors.toList()); } else{ incentiveActivityRecord = dbRecords.stream() .filter(r -> { From b03267c68cf4e9229eaf05e4e6cbca1f080c49f8 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 15:34:30 +0530 Subject: [PATCH 107/237] fix issue of default activity approval status --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 76859a8cb..54ae163f9 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1272,6 +1272,11 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci ) ) .collect(Collectors.toList()); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); } else{ incentiveActivityRecord = dbRecords.stream() .filter(r -> { From 566e72ac880705ba2298ef522f2b74c560e019ac Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 15:43:36 +0530 Subject: [PATCH 108/237] fix issue of default activity approval status --- .../impl/SupervisorDashboardServiceImpl.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 54ae163f9..25a9ce838 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1249,18 +1249,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci r.getActivityId() ) ); - }else if(approvalStatusID.equals(106)){ - incentiveActivityRecord = dbRecords.stream() - .filter(r->!r.getIsClaimed() && r.getApprovalStatus().equals(102)).peek(r->{r.setApprovalStatus(106);}).collect(Collectors.toList()); - totalAmount = incentiveActivityRecord.stream() - .map(IncentiveActivityRecord::getAmount) - .filter(Objects::nonNull) - .mapToLong(Long::longValue) - .sum(); - }else if(approvalStatusID.equals(0)){ - incentiveActivityRecord = dbRecords.stream() - .filter(r->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed()) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104))).collect(Collectors.toList()); - }if (Objects.equals(approvalStatusID, 103)) { + }else if (Objects.equals(approvalStatusID, 103)) { // ANM/CHO can view all rejected activities // that are unclaimed @@ -1277,6 +1266,17 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .filter(Objects::nonNull) .mapToLong(Long::longValue) .sum(); + }else if(approvalStatusID.equals(106)){ + incentiveActivityRecord = dbRecords.stream() + .filter(r->!r.getIsClaimed() && r.getApprovalStatus().equals(102)).peek(r->{r.setApprovalStatus(106);}).collect(Collectors.toList()); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); + }else if(approvalStatusID.equals(0)){ + incentiveActivityRecord = dbRecords.stream() + .filter(r->((r.getApprovalStatus().equals(102) && r.getIsClaimed()) ||(r.getApprovalStatus().equals(102) && !r.getIsClaimed()) || r.getApprovalStatus().equals(103) || r.getApprovalStatus().equals(105) || r.getApprovalStatus().equals(101) || r.getApprovalStatus().equals(104))).collect(Collectors.toList()); } else{ incentiveActivityRecord = dbRecords.stream() .filter(r -> { From 0d53a7c519ab0cd13922b4a783e6143901cd94fa Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 15:52:01 +0530 Subject: [PATCH 109/237] fix issue of default activity approval status --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 25a9ce838..c87883d4b 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1046,9 +1046,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveActivityRecord = dbRecords.stream() .filter(record -> Objects.equals(record.getApprovalStatus(), 103) - && !Boolean.TRUE.equals( - record.getIsClaimed() - ) && Boolean.TRUE.equals( record.getIsDefaultActivity() ) @@ -1256,9 +1253,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveActivityRecord = dbRecords.stream() .filter(record -> Objects.equals(record.getApprovalStatus(), 103) - && !Boolean.TRUE.equals( - record.getIsClaimed() - ) + ) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() From 13a68cca2ed203caf3a260e3b645122bd5a87da7 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 16:03:24 +0530 Subject: [PATCH 110/237] fix issue of default activity approval status --- .../service/impl/IncentiveServiceImpl.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index c2440ee2e..961682eda 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -545,20 +545,23 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) .collect(Collectors.toList()); }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - records = records.stream() - .filter(record -> - validActivityIds.contains(record.getActivityId()) - ) - .filter(record -> - !Boolean.TRUE.equals( - record.getIsDefaultActivity() - ) + if(request.getApprovalStatus().equals(102) || request.getApprovalStatus().equals(105)){ + records = records.stream() + .filter(record -> + validActivityIds.contains(record.getActivityId()) + ) + .filter(record -> + !Boolean.TRUE.equals( + record.getIsDefaultActivity() + ) + + || Boolean.TRUE.equals( + record.getIsApproved() + ) + ) + .collect(Collectors.toList()); + } - || Boolean.TRUE.equals( - record.getIsApproved() - ) - ) - .collect(Collectors.toList()); logger.info( "ANM/CHO records after default activity filter: {}", From 453d3afb8616fd085b30a93376bd830a1b6a5ae6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 9 Sep 2026 16:40:41 +0530 Subject: [PATCH 111/237] change status to unclaimed after end of month --- .../flw/repo/iemr/IncentiveRecordRepo.java | 24 +++ .../impl/IncentiveMonthlyScheduler.java | 49 ++++++ .../service/impl/IncentiveServiceImpl.java | 158 +++--------------- 3 files changed, 95 insertions(+), 136 deletions(-) create mode 100644 src/main/java/com/iemr/flw/service/impl/IncentiveMonthlyScheduler.java diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 738a9d452..41d29bf52 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -466,4 +466,28 @@ int updateClaimStatusByAshaAndIncentiveIds( @Param("calimedDate") Timestamp calimedDate, @Param("incentiveId") Long incentiveId ); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Transactional + @Query(""" + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = 102, + iar.isClaimed = false, + iar.calimedDate = NULL, + iar.approvalDate = NULL, + iar.reason = NULL, + iar.otherReason = NULL, + iar.verifiedByUserId = NULL, + iar.verifiedByUserName = NULL, + iar.updatedDate = :updatedDate, + iar.updatedBy = :updatedBy + WHERE iar.approvalStatus = 103 + AND iar.isClaimed = true + AND iar.endDate < :currentMonthStart +""") + int resetRejectedIncentivesForNewMonth( + @Param("currentMonthStart") Timestamp currentMonthStart, + @Param("updatedDate") Timestamp updatedDate, + @Param("updatedBy") String updatedBy + ); } diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveMonthlyScheduler.java b/src/main/java/com/iemr/flw/service/impl/IncentiveMonthlyScheduler.java new file mode 100644 index 000000000..2624f5644 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveMonthlyScheduler.java @@ -0,0 +1,49 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.repo.iemr.IncentiveRecordRepo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +@Component +@RequiredArgsConstructor +@Slf4j +public class IncentiveMonthlyScheduler { + + private static final ZoneId INDIA_ZONE = + ZoneId.of("Asia/Kolkata"); + @Autowired + private IncentiveRecordRepo recordRepo; + + @Scheduled(cron = "0 5 0 1 * *", zone = "Asia/Kolkata") + public void resetRejectedIncentivesForNewMonth() { + + LocalDate firstDayOfCurrentMonth = + LocalDate.now(INDIA_ZONE).withDayOfMonth(1); + + Timestamp currentMonthStart = + Timestamp.valueOf(firstDayOfCurrentMonth.atStartOfDay()); + + Timestamp updatedDate = + Timestamp.from(ZonedDateTime.now(INDIA_ZONE).toInstant()); + + int updatedCount = + recordRepo.resetRejectedIncentivesForNewMonth( + currentMonthStart, + updatedDate, + "SYSTEM" + ); + + log.info( + "Rejected incentives reset successfully. Updated records: {}", + updatedCount + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 961682eda..afe769e74 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -30,9 +30,7 @@ import org.springframework.web.multipart.MultipartFile; import java.sql.Timestamp; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.Month; +import java.time.*; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -339,140 +337,28 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); return gson.toJson(finalDtos); } -// @Override -// public String getAllIncentivesByUserId(GetBenRequestHandler request) { -// int page = 0; -// int size = 20; -// Page pageResult; -// List finalDtos = new ArrayList<>(); -// -// Integer stateCode = userService.getUserDetail(request.getAshaId()).getStateId(); -// String userName = userService.getUserDetail(request.getAshaId()).getUserName(); -// try { -// -// if (stateCode.equals(StateCode.AM.getStateCode())) { -// checkMonthlyAshaIncentive(request.getAshaId()); -// } -// if (stateCode.equals(StateCode.CG.getStateCode())) { -// checkMonthlyAshaIncentiveForCg(request.getAshaId()); -// -// } -// -// } catch (Exception e) { -// logger.error("Error in checkMonthlyAshaIncentive: ", e); -// } -// -// try { -// addIncentiveForIronTablets(request.getAshaId()); -// incentiveOfNcdReferal(request.getAshaId(), request.getVillageID()); -// -// } catch (Exception e) { -// logger.error("Error in incentiveOfNcdReferal: ", e); -// } -// -// boolean isCG = stateCode != null && stateCode.equals(StateCode.CG.getStateCode()); -// -// do { -// -// Pageable pageable = PageRequest.of( -// page, -// size, -// Sort.by("id").descending() // latest first -// ); -// -// pageResult = recordRepo.findRecordsByAsha( -// request.getAshaId(), -// pageable -// ); -// -// List entities = pageResult.getContent(); -// -// if (entities.isEmpty()) { -// return new Gson().toJson(Collections.emptyList()); -// } -// -// // Step 2: Collect all activityIds — fetch valid ones in ONE query -// List activityIds = entities.stream() -// .map(IncentiveActivityRecord::getActivityId) -// .distinct() -// .collect(Collectors.toList()); -// -// // Single bulk query instead of N individual findIncentiveMasterById() calls -// Set validActivityIds = isCG -// ? incentivesRepo.findValidActivityIds(activityIds, true) -// : incentivesRepo.findValidActivityIds(activityIds, false); -// -// // Filter entities based on valid activity IDs -// entities = entities.stream() -// .filter(e -> validActivityIds.contains(e.getActivityId())) -// .collect(Collectors.toList()); -// -// // Step 3: Collect all benIds that need name lookup (name == null and benId > 0) -// List benIdsToFetch = entities.stream() -// .filter(e -> e.getName() == null && e.getBenId() != null && e.getBenId() > 0) -// .map(IncentiveActivityRecord::getBenId) -// .distinct() -// .collect(Collectors.toList()); -// -// // Step 4: Bulk fetch all beneficiary names in ONE query instead of 3 queries per record -// Map benIdToNameMap = new HashMap<>(); -// if (!benIdsToFetch.isEmpty()) { -// List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); -// for (Object[] row : benDetails) { -// Long benId = ((Number) row[0]).longValue(); -// String first = row[1] != null ? (String) row[1] : ""; -// String last = row[2] != null ? (String) row[2] : ""; -// benIdToNameMap.put(benId, (first + " " + last).trim()); -// } -// } -// -// // Step 5: Map entities to DTOs -// List dtos = entities.stream().map(entry -> { -// if (entry.getName() == null) { -// if (entry.getBenId() != null && entry.getBenId() > 0) { -// String name = benIdToNameMap.getOrDefault(entry.getBenId(), ""); -// entry.setName(name); -// if (isCG) { -// entry.setIsEligible(true); -// } -// } else { -// entry.setName(""); -// } -// if (entry.getVerifiedByUserId() != null) { -// entry.setSupervisorRole(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getRoleName()); -// entry.setVerifiedByUserName(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getName()); -// -// } -// if (entry.getAshaId() != null) { -// if (entry.getCreatedBy() == null) { -// entry.setCreatedBy(userName); -// } -// -// if (entry.getUpdatedBy() == null) { -// entry.setUpdatedBy(userName); -// } -// -// if (entry.getIsEligible() == null) { -// entry.setIsEligible(true); -// } -// } -// -// -// } -// return modelMapper.map(entry, IncentiveRecordDTO.class); -// }).collect(Collectors.toList()); -// finalDtos.addAll(dtos); -// -// page++; -// -// } while (pageResult.hasNext()); -// -// -// -// Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); -// return gson.toJson(finalDtos); -// } + + @Transactional + public void resetRejectedIncentivesForPreviousMonths() { + + ZoneId zoneId = ZoneId.of("Asia/Kolkata"); + + LocalDate firstDayOfCurrentMonth = + LocalDate.now(zoneId).withDayOfMonth(1); + + Timestamp currentMonthStart = + Timestamp.valueOf(firstDayOfCurrentMonth.atStartOfDay()); + + Timestamp now = + Timestamp.from(ZonedDateTime.now(zoneId).toInstant()); + + recordRepo.resetRejectedIncentivesForNewMonth( + currentMonthStart, + now, + "SYSTEM" + ); + } // ================= GROUPED SUMMARY ================= @Override public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Integer userId) { From 1af102dafaeb632d7d0ebcd7ea6d27662e13a7b1 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 13:24:04 +0530 Subject: [PATCH 112/237] change status to unclaimed after end of month --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index c87883d4b..10898189f 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1000,9 +1000,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveActivityRecord = dbRecords.stream() .filter(record -> Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals( - record.getApprovalStatus(), 105 - ) ) .filter(record -> Boolean.TRUE.equals( From ec04e7bd16086c392337b6859db0b7c5bcca977b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 13:33:40 +0530 Subject: [PATCH 113/237] change status to unclaimed after end of month --- .../impl/SupervisorDashboardServiceImpl.java | 169 ++++++++++++------ 1 file changed, 114 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 10898189f..9cccbaaf0 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -922,62 +922,121 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate); if (Objects.equals(approvalStatusID, 104) && isOverDue) { + if("ASHA Supervisor".equalsIgnoreCase(roleName)){ + incentiveActivityRecord = dbRecords.stream() + + // Overdue applicable statuses + + .filter(record -> + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals(record.getApprovalStatus(), 104) + ) + + // Role-wise activity filtering + .filter(record -> { + + boolean isDefault = + Boolean.TRUE.equals( + record.getIsDefaultActivity() + ); + + boolean isApproved = + Boolean.TRUE.equals( + record.getIsApproved() + ); + + if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { + // Supervisor: only approved default activities + return isDefault && isApproved; + } + + if ("ANM".equalsIgnoreCase(roleName) + || "CHO".equalsIgnoreCase(roleName)) { + // ANM/CHO: + // all non-default activities + // default activity only when approved + return !isDefault || isApproved; + } + + return false; + }) + + .peek(record -> { + logger.info( + "Overdue record matched: role={}, ashaId={}, " + + "recordId={}, oldStatus={}, default={}, " + + "approved={}, claimedDate={}", + roleName, + ashaId, + record.getId(), + record.getApprovalStatus(), + record.getIsDefaultActivity(), + record.getIsApproved(), + record.getCalimedDate() + ); + + record.setApprovalStatus(104); + }) + .collect(Collectors.toList()); + }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)){ + incentiveActivityRecord = dbRecords.stream() + + // Overdue applicable statuses + + .filter(record -> + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals(record.getApprovalStatus(), 104) + || Objects.equals(record.getApprovalStatus(), 105) + ) + + // Role-wise activity filtering + .filter(record -> { + + boolean isDefault = + Boolean.TRUE.equals( + record.getIsDefaultActivity() + ); + + boolean isApproved = + Boolean.TRUE.equals( + record.getIsApproved() + ); + + if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { + // Supervisor: only approved default activities + return isDefault && isApproved; + } + + if ("ANM".equalsIgnoreCase(roleName) + || "CHO".equalsIgnoreCase(roleName)) { + // ANM/CHO: + // all non-default activities + // default activity only when approved + return !isDefault || isApproved; + } + + return false; + }) + + .peek(record -> { + logger.info( + "Overdue record matched: role={}, ashaId={}, " + + "recordId={}, oldStatus={}, default={}, " + + "approved={}, claimedDate={}", + roleName, + ashaId, + record.getId(), + record.getApprovalStatus(), + record.getIsDefaultActivity(), + record.getIsApproved(), + record.getCalimedDate() + ); + + record.setApprovalStatus(104); + }) + .collect(Collectors.toList()); + } - incentiveActivityRecord = dbRecords.stream() - - // Overdue applicable statuses - .filter(record -> - Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals(record.getApprovalStatus(), 104) - || Objects.equals(record.getApprovalStatus(), 105) - ) - - // Role-wise activity filtering - .filter(record -> { - - boolean isDefault = - Boolean.TRUE.equals( - record.getIsDefaultActivity() - ); - - boolean isApproved = - Boolean.TRUE.equals( - record.getIsApproved() - ); - - if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { - // Supervisor: only approved default activities - return isDefault && isApproved; - } - - if ("ANM".equalsIgnoreCase(roleName) - || "CHO".equalsIgnoreCase(roleName)) { - // ANM/CHO: - // all non-default activities - // default activity only when approved - return !isDefault || isApproved; - } - - return false; - }) - - .peek(record -> { - logger.info( - "Overdue record matched: role={}, ashaId={}, " + - "recordId={}, oldStatus={}, default={}, " + - "approved={}, claimedDate={}", - roleName, - ashaId, - record.getId(), - record.getApprovalStatus(), - record.getIsDefaultActivity(), - record.getIsApproved(), - record.getCalimedDate() - ); - - record.setApprovalStatus(104); - }) - .collect(Collectors.toList()); overDue = incentiveActivityRecord.size(); From 3df3c52c86cec512190d32830070e63f2c0f2173 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 14:43:53 +0530 Subject: [PATCH 114/237] change status to unclaimed after end of month --- .../java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java index fab2b4654..4875c9d8d 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -184,6 +184,8 @@ List getIncentiveStatusByAshaIdsForAnm( + "AND iar.created_date >= :startDate " + "AND iar.is_claimed = true " + "AND iar.is_default_activity = true " + + "AND iar.is_default_activity = true " + + "AND iar.is_approved = false " + "AND iar.created_date < :endDate " + "GROUP BY iar.asha_id", nativeQuery = true) From b7be2a2768c88dbd51a59b79f98843a134b0b581 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 14:47:42 +0530 Subject: [PATCH 115/237] change status to unclaimed after end of month --- .../impl/SupervisorDashboardServiceImpl.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 9cccbaaf0..49b82ec27 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -947,7 +947,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { // Supervisor: only approved default activities - return isDefault && isApproved; + return isDefault || isApproved; } if ("ANM".equalsIgnoreCase(roleName) @@ -1004,7 +1004,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { // Supervisor: only approved default activities - return isDefault && isApproved; + return isDefault || isApproved; } if ("ANM".equalsIgnoreCase(roleName) @@ -1035,16 +1035,17 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci record.setApprovalStatus(104); }) .collect(Collectors.toList()); + overDue = incentiveActivityRecord.size(); + + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); } - overDue = incentiveActivityRecord.size(); - totalAmount = incentiveActivityRecord.stream() - .map(IncentiveActivityRecord::getAmount) - .filter(Objects::nonNull) - .mapToLong(Long::longValue) - .sum(); logger.info( "Overdue final: role={}, ashaId={}, count={}, totalAmount={}", From 85e97e88f64b04143b28447111bb3e5ab480bb1e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 14:58:31 +0530 Subject: [PATCH 116/237] change status to unclaimed after end of month --- .../impl/SupervisorDashboardServiceImpl.java | 36 ++----------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 49b82ec27..6e8c851c0 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -928,38 +928,10 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci // Overdue applicable statuses .filter(record -> - Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals(record.getApprovalStatus(), 104) + (Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals(record.getApprovalStatus(), 104)) && record.getIsDefaultActivity() ) - // Role-wise activity filtering - .filter(record -> { - - boolean isDefault = - Boolean.TRUE.equals( - record.getIsDefaultActivity() - ); - - boolean isApproved = - Boolean.TRUE.equals( - record.getIsApproved() - ); - - if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { - // Supervisor: only approved default activities - return isDefault || isApproved; - } - - if ("ANM".equalsIgnoreCase(roleName) - || "CHO".equalsIgnoreCase(roleName)) { - // ANM/CHO: - // all non-default activities - // default activity only when approved - return !isDefault || isApproved; - } - - return false; - }) .peek(record -> { logger.info( @@ -1002,10 +974,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci record.getIsApproved() ); - if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { - // Supervisor: only approved default activities - return isDefault || isApproved; - } if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { From 65fd2279903ee6f35a35c3c387ff34583d61232b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:10:17 +0530 Subject: [PATCH 117/237] change status to unclaimed after end of month --- .../service/impl/SupervisorDashboardServiceImpl.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 6e8c851c0..273025d12 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1003,16 +1003,16 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci record.setApprovalStatus(104); }) .collect(Collectors.toList()); - overDue = incentiveActivityRecord.size(); - totalAmount = incentiveActivityRecord.stream() - .map(IncentiveActivityRecord::getAmount) - .filter(Objects::nonNull) - .mapToLong(Long::longValue) - .sum(); } + overDue = incentiveActivityRecord.size(); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); logger.info( From 797827b3409b3c0b33c48f8a5fec431299edc6bb Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:16:37 +0530 Subject: [PATCH 118/237] change status to unclaimed after end of month --- .../flw/service/impl/IncentiveServiceImpl.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index afe769e74..92f7371a4 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -427,9 +427,16 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege // Filter records based on valid activity IDs if(isCG){ if("ASHA Supervisor".equalsIgnoreCase(roleName)){ - records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) - .collect(Collectors.toList()); + if(request.getApprovalStatus().equals(104)){ + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity() && r.getApprovalStatus().equals(102)) + .collect(Collectors.toList()); + }else { + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity() && r.getApprovalStatus().equals(102)) + .collect(Collectors.toList()); + } + }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { if(request.getApprovalStatus().equals(102) || request.getApprovalStatus().equals(105)){ records = records.stream() @@ -449,6 +456,8 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege } + + logger.info( "ANM/CHO records after default activity filter: {}", records.size() From bdd271b10a91ed15475f6713dc390d10a2b1af9f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:17:20 +0530 Subject: [PATCH 119/237] change status to unclaimed after end of month --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 92f7371a4..7b943ea7e 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -433,7 +433,7 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .collect(Collectors.toList()); }else { records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity() && r.getApprovalStatus().equals(102)) + .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) .collect(Collectors.toList()); } From d04c2d507f867a5c1ca97f63268e5388637ec607 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:37:24 +0530 Subject: [PATCH 120/237] change status to unclaimed after end of month --- .../impl/SupervisorDashboardServiceImpl.java | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 273025d12..ae246abbb 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -956,36 +956,14 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci // Overdue applicable statuses .filter(record -> - Objects.equals(record.getApprovalStatus(), 102) + (Objects.equals(record.getApprovalStatus(), 102) || Objects.equals(record.getApprovalStatus(), 104) - || Objects.equals(record.getApprovalStatus(), 105) + || Objects.equals(record.getApprovalStatus(), 105)) || (record.getIsDefaultActivity() && record.getApprovalStatus().equals(105) || (record.getIsDefaultActivity() && record.getIsApproved())) ) // Role-wise activity filtering - .filter(record -> { - - boolean isDefault = - Boolean.TRUE.equals( - record.getIsDefaultActivity() - ); - - boolean isApproved = - Boolean.TRUE.equals( - record.getIsApproved() - ); - if ("ANM".equalsIgnoreCase(roleName) - || "CHO".equalsIgnoreCase(roleName)) { - // ANM/CHO: - // all non-default activities - // default activity only when approved - return !isDefault || isApproved; - } - - return false; - }) - .peek(record -> { logger.info( "Overdue record matched: role={}, ashaId={}, " + From ec08d9a7f0c8d235b04884aa1646c32e943064c0 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:47:07 +0530 Subject: [PATCH 121/237] change status to unclaimed after end of month --- .../service/impl/IncentiveServiceImpl.java | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 7b943ea7e..d574767ef 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -465,9 +465,41 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege } }else { - records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) - .collect(Collectors.toList()); + if(request.getApprovalStatus().equals(104)){ + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .filter(r -> { + if (Objects.equals(request.getApprovalStatus(), 104)) { + + // All status 102 records + boolean status102 = + Objects.equals(r.getApprovalStatus(), 102); + + // Status 105 only for default activities + boolean status105 = + Objects.equals(r.getApprovalStatus(), 105) + && Boolean.TRUE.equals( + r.getIsDefaultActivity() + ); + + // Existing overdue records + boolean status104 = + Objects.equals(r.getApprovalStatus(), 104); + + return status102 || status105 || status104; + } + + return Objects.equals( + r.getApprovalStatus(), + request.getApprovalStatus() + ); + }) + .collect(Collectors.toList()); + }else { + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .collect(Collectors.toList()); + } } From edcac638a60ae4959067f6659416ef37bd671bc3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:48:27 +0530 Subject: [PATCH 122/237] change status to unclaimed after end of month --- .../service/impl/IncentiveServiceImpl.java | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index d574767ef..62f341573 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -453,6 +453,36 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege ) ) .collect(Collectors.toList()); + }else if(request.getApprovalStatus().equals(104)){ + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .filter(r -> { + if (Objects.equals(request.getApprovalStatus(), 104)) { + + // All status 102 records + boolean status102 = + Objects.equals(r.getApprovalStatus(), 102); + + // Status 105 only for default activities + boolean status105 = + Objects.equals(r.getApprovalStatus(), 105) + && Boolean.TRUE.equals( + r.getIsDefaultActivity() + ); + + // Existing overdue records + boolean status104 = + Objects.equals(r.getApprovalStatus(), 104); + + return status102 || status105 || status104; + } + + return Objects.equals( + r.getApprovalStatus(), + request.getApprovalStatus() + ); + }) + .collect(Collectors.toList()); } @@ -465,41 +495,9 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege } }else { - if(request.getApprovalStatus().equals(104)){ - records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) - .filter(r -> { - if (Objects.equals(request.getApprovalStatus(), 104)) { - - // All status 102 records - boolean status102 = - Objects.equals(r.getApprovalStatus(), 102); - - // Status 105 only for default activities - boolean status105 = - Objects.equals(r.getApprovalStatus(), 105) - && Boolean.TRUE.equals( - r.getIsDefaultActivity() - ); - - // Existing overdue records - boolean status104 = - Objects.equals(r.getApprovalStatus(), 104); - - return status102 || status105 || status104; - } - - return Objects.equals( - r.getApprovalStatus(), - request.getApprovalStatus() - ); - }) - .collect(Collectors.toList()); - }else { - records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) - .collect(Collectors.toList()); - } + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .collect(Collectors.toList()); } From 800c031d9b062521147f705b1dc7a39f20bd7ea8 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:48:59 +0530 Subject: [PATCH 123/237] change status to unclaimed after end of month --- .../java/com/iemr/flw/service/impl/IncentiveServiceImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 62f341573..51114f68e 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -483,6 +483,10 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege ); }) .collect(Collectors.toList()); + }else { + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .collect(Collectors.toList()); } From ce1e4f7dba0ed5d5c366e698c261f25a7add68b1 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:57:58 +0530 Subject: [PATCH 124/237] change status to unclaimed after end of month --- .../flw/service/impl/IncentiveServiceImpl.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 51114f68e..72f757f8c 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -459,16 +459,22 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .filter(r -> { if (Objects.equals(request.getApprovalStatus(), 104)) { - // All status 102 records + boolean isDefault = + Boolean.TRUE.equals(r.getIsDefaultActivity()); + + boolean isApproved = + Boolean.TRUE.equals(r.getIsApproved()); + + // All non-default 102 records, + // and approved default 102 records boolean status102 = - Objects.equals(r.getApprovalStatus(), 102); + Objects.equals(r.getApprovalStatus(), 102) + && (!isDefault || isApproved); - // Status 105 only for default activities + // Default 105 records, regardless of isApproved boolean status105 = Objects.equals(r.getApprovalStatus(), 105) - && Boolean.TRUE.equals( - r.getIsDefaultActivity() - ); + && isDefault; // Existing overdue records boolean status104 = From f8a32d1e9bff4d17529276b31fba665d8123627a Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 15:59:20 +0530 Subject: [PATCH 125/237] change status to unclaimed after end of month --- .../impl/SupervisorDashboardServiceImpl.java | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index ae246abbb..c3c496753 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -950,20 +950,44 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci record.setApprovalStatus(104); }) .collect(Collectors.toList()); + + overDue = incentiveActivityRecord.size(); + + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); }else if("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)){ incentiveActivityRecord = dbRecords.stream() + .filter(record -> { - // Overdue applicable statuses + boolean isDefault = + Boolean.TRUE.equals(record.getIsDefaultActivity()); - .filter(record -> - (Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals(record.getApprovalStatus(), 104) - || Objects.equals(record.getApprovalStatus(), 105)) || (record.getIsDefaultActivity() && record.getApprovalStatus().equals(105) || (record.getIsDefaultActivity() && record.getIsApproved())) - ) + boolean isApproved = + Boolean.TRUE.equals(record.getIsApproved()); - // Role-wise activity filtering + Integer status = record.getApprovalStatus(); + // 102: + // Non-default OR approved default activity + boolean status102 = + Objects.equals(status, 102) + && (!isDefault || isApproved); + // 105: + // Only default activity + boolean status105 = + Objects.equals(status, 105) + && isDefault; + + // Already overdue + boolean status104 = + Objects.equals(status, 104); + + return status102 || status105 || status104; + }) .peek(record -> { logger.info( "Overdue record matched: role={}, ashaId={}, " + @@ -982,15 +1006,15 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }) .collect(Collectors.toList()); - } + overDue = incentiveActivityRecord.size(); - overDue = incentiveActivityRecord.size(); + totalAmount = incentiveActivityRecord.stream() + .map(IncentiveActivityRecord::getAmount) + .filter(Objects::nonNull) + .mapToLong(Long::longValue) + .sum(); - totalAmount = incentiveActivityRecord.stream() - .map(IncentiveActivityRecord::getAmount) - .filter(Objects::nonNull) - .mapToLong(Long::longValue) - .sum(); + } logger.info( From 3b08024b2dfaf2d669797208d80563d9cfec98e9 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 17:17:51 +0530 Subject: [PATCH 126/237] change status to unclaimed after end of month --- .../iemr/flw/service/impl/IncentiveServiceImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 72f757f8c..4e3fd6dfa 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -377,9 +377,13 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .stream() .filter(r -> r.getCreatedDate() != null - && r.getEndDate() != null - && r.getEndDate().toLocalDateTime().getMonthValue() == request.getMonth() - && r.getEndDate().toLocalDateTime().getYear() == request.getYear() + && r.getStartDate() != null + && r.getStartDate() + .toLocalDateTime() + .getMonthValue() == request.getMonth() + && r.getStartDate() + .toLocalDateTime() + .getYear() == request.getYear() && Boolean.TRUE.equals(r.getIsClaimed()) && ( // 104 => 102 OR 105 From 63deeaa007f0495369ab5a4ef2f4d7b95779fa4f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 10 Sep 2026 17:26:05 +0530 Subject: [PATCH 127/237] change status to unclaimed after end of month --- .../service/impl/IncentiveServiceImpl.java | 101 +++++++++++++----- 1 file changed, 74 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 4e3fd6dfa..033ad8f05 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -366,8 +366,18 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege LocalDate start = LocalDate.of(request.getYear(), request.getMonth(), 1); LocalDate end = start.withDayOfMonth(start.lengthOfMonth()); - Timestamp startTs = Timestamp.valueOf(start.atStartOfDay()); - Timestamp endTs = Timestamp.valueOf(end.atTime(23, 59, 59)); + + LocalDate monthStart = LocalDate.of( + request.getYear(), + request.getMonth(), + 1 + ); + + Timestamp startTs = + Timestamp.valueOf(monthStart.atStartOfDay()); + + Timestamp nextMonthTs = + Timestamp.valueOf(monthStart.plusMonths(1).atStartOfDay()); Integer villageID = userRepo.getUserRole(request.getUserId()).get(0).getStateId(); boolean isCG = villageID != null && villageID.intValue() == StateCode.CG.getStateCode(); @@ -377,46 +387,83 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .stream() .filter(r -> r.getCreatedDate() != null - && r.getStartDate() != null - && r.getStartDate() + + // Month filter using createdDate + && r.getCreatedDate() .toLocalDateTime() - .getMonthValue() == request.getMonth() - && r.getStartDate() + .getMonthValue() + == request.getMonth() + + && r.getCreatedDate() .toLocalDateTime() - .getYear() == request.getYear() + .getYear() + == request.getYear() + && Boolean.TRUE.equals(r.getIsClaimed()) + && ( - // 104 => 102 OR 105 - (Objects.equals(request.getApprovalStatus(), 104) - && ( - Objects.equals(r.getApprovalStatus(), 102) - || Objects.equals(r.getApprovalStatus(), 105) - ) + // Overdue: 102, 104 or 105 + ( + Objects.equals( + request.getApprovalStatus(), + 104 + ) + && ( + Objects.equals( + r.getApprovalStatus(), + 102 + ) + || Objects.equals( + r.getApprovalStatus(), + 104 + ) + || Objects.equals( + r.getApprovalStatus(), + 105 + ) + ) ) || - // 105 => 101 OR 105 - (Objects.equals(request.getApprovalStatus(), 105) - && ( - Objects.equals(r.getApprovalStatus(), 101) - || Objects.equals(r.getApprovalStatus(), 105) - ) + // Verified: 101 or 105 + ( + Objects.equals( + request.getApprovalStatus(), + 105 + ) + && ( + Objects.equals( + r.getApprovalStatus(), + 101 + ) + || Objects.equals( + r.getApprovalStatus(), + 105 + ) + ) ) || - // Normal status - (!Objects.equals(request.getApprovalStatus(), 104) - && !Objects.equals(request.getApprovalStatus(), 105) - && Objects.equals( - r.getApprovalStatus(), - request.getApprovalStatus() - ) + // Other statuses + ( + !Objects.equals( + request.getApprovalStatus(), + 104 + ) + && !Objects.equals( + request.getApprovalStatus(), + 105 + ) + && Objects.equals( + r.getApprovalStatus(), + request.getApprovalStatus() + ) ) ) ) - .toList(); + .collect(Collectors.toList()); // Bulk fetch valid activity IDs — state wise From cdef0cf0840e5fb5b2c044e5e3140102ebc9dfc3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 11 Sep 2026 11:26:50 +0530 Subject: [PATCH 128/237] change status to unclaimed after end of month --- .../service/impl/IncentiveServiceImpl.java | 68 +++++++++++++++++-- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 033ad8f05..4da29ff43 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -662,17 +662,75 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { List records = recordRepo.findRecordsByAsha(request.getUserId()) .stream() - .filter(r -> r.getActivityId() != null - && r.getActivityId().equals(request.getActivityId()) - && r.getCreatedDate() != null - && !r.getCreatedDate().before(startTs) - && r.getCreatedDate().before(endTs)) + .filter(r -> + r.getActivityId() != null + && Objects.equals( + r.getActivityId(), + request.getActivityId() + ) + && r.getCreatedDate() != null + && !r.getCreatedDate().before(startTs) + && r.getCreatedDate().before(endTs) + ) + .filter(r -> { + + Integer requestedStatus = + request.getApprovalStatus(); + + Integer recordStatus = + r.getApprovalStatus(); + + boolean isDefault = + Boolean.TRUE.equals( + r.getIsDefaultActivity() + ); + + boolean isApproved = + Boolean.TRUE.equals( + r.getIsApproved() + ); + + // Overdue + if (Objects.equals(requestedStatus, 104)) { + + // 102 non-default records OR approved default records + boolean status102 = + Objects.equals(recordStatus, 102) + && (!isDefault || isApproved); + + // 105 only for default activities + boolean status105 = + Objects.equals(recordStatus, 105) + && isDefault; + + // Existing overdue records + boolean status104 = + Objects.equals(recordStatus, 104); + + return status102 + || status105 + || status104; + } + + // Verified: 101 or 105 + if (Objects.equals(requestedStatus, 105)) { + return Objects.equals(recordStatus, 101) + || Objects.equals(recordStatus, 105); + } + + // Pending, rejected or other status + return Objects.equals( + recordStatus, + requestedStatus + ); + }) .collect(Collectors.toList()); if (records.isEmpty()) { return new Gson().toJson(new ArrayList<>()); } + // 🔹 Get beneficiary names Set benIds = records.stream() .map(IncentiveActivityRecord::getBenId) From 37f1c148487c5fbd220126f1cb64dd5f0b12aab6 Mon Sep 17 00:00:00 2001 From: vaibhav45sktech <232676907+vaibhav45sktech@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:52:49 +0530 Subject: [PATCH 129/237] feat(badges): carry a stable award key on the earned log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (user_id, badge_id, level) is not unique for every badge. Quarterly badges are re-earned each quarter at the same level, and per-case badges once per beneficiary, so two genuine awards collided on the old constraint: the second was silently skipped as a duplicate on upload and could not be told apart on restore. badge_earned gains award_key and the unique key becomes (user_id, badge_id, level, award_key). The key is a quarter key such as "2026-Q3", or an opaque digest for per-case awards, and empty for streak and cumulative badges, which are earned once per level. It is never a beneficiary identifier. The device hashes those before they are sent, so this column can separate two awards without the server learning who either was about (Badge LLD §4). A missing key is stored as empty rather than rejected. That is what a streak or cumulative badge sends, and also what a client predating the field sends for everything, so such a client keeps behaving exactly as it did before. Verified: 8 badge tests pass, including two new ones covering two awards of the same level under different keys, and a null key from an older client. The rest of the suite does not compile on this branch's base and was excluded from the run, unchanged. --- .../com/iemr/flw/domain/iemr/BadgeEarned.java | 21 ++++++++- .../com/iemr/flw/dto/iemr/BadgeEarnedDTO.java | 7 +++ .../iemr/flw/repo/iemr/BadgeEarnedRepo.java | 3 +- .../com/iemr/flw/service/BadgeService.java | 17 +++++-- .../flw/controller/BadgeControllerTest.java | 2 +- .../iemr/flw/service/BadgeServiceTest.java | 46 +++++++++++++++++-- 6 files changed, 84 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/BadgeEarned.java b/src/main/java/com/iemr/flw/domain/iemr/BadgeEarned.java index b73864257..382113f94 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/BadgeEarned.java +++ b/src/main/java/com/iemr/flw/domain/iemr/BadgeEarned.java @@ -13,13 +13,18 @@ * Append-only badge award log (Badge LLD §4.1, "once earned, never revoked"). * The unique key mirrors the device's local constraint so re-uploads after a * reinstall or a retried sync are idempotent. + * + * The key includes award_key because (user, badge, level) is not unique for every badge. + * Quarterly badges are re-earned each quarter at the same level, and per-case badges are + * earned once per beneficiary, so without it the second and later awards collapse into the + * first on upload and cannot be told apart on restore. */ @Entity @Data @Table(name = "badge_earned", schema = "db_iemr", uniqueConstraints = @UniqueConstraint( - name = "uk_badge_earned_user_badge_level", - columnNames = {"user_id", "badge_id", "level"})) + name = "uk_badge_earned_user_badge_level_key", + columnNames = {"user_id", "badge_id", "level", "award_key"})) public class BadgeEarned { @Id @@ -35,6 +40,18 @@ public class BadgeEarned { @Column(name = "level", nullable = false) private Integer level; + /** + * What makes two awards of the same badge and level different: a quarter key such as + * "2026-Q3", or an opaque digest for per-case badges. Empty for streak and cumulative + * badges, which are earned once per level. + * + * Never a beneficiary identifier. The device hashes those before they are sent, so this + * column can separate two awards without the server learning who either was about + * (Badge LLD §4). + */ + @Column(name = "award_key", length = 64, nullable = false) + private String awardKey = ""; + /** Epoch millis when the device awarded it. */ @Column(name = "earned_at", nullable = false) private Long earnedAt; diff --git a/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedDTO.java b/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedDTO.java index 9ce8d6a79..b7bdbb5a0 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/BadgeEarnedDTO.java @@ -12,4 +12,11 @@ public class BadgeEarnedDTO { private String badgeId; private Integer level; private Long earnedAt; + + /** + * Stable discriminator for badges that can be earned more than once at the same level. + * A quarter key, or an opaque digest for per-case awards; empty otherwise. Never a + * beneficiary identifier — see {@link com.iemr.flw.domain.iemr.BadgeEarned#getAwardKey()}. + */ + private String awardKey; } diff --git a/src/main/java/com/iemr/flw/repo/iemr/BadgeEarnedRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BadgeEarnedRepo.java index 219571a55..6452e6225 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/BadgeEarnedRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/BadgeEarnedRepo.java @@ -10,5 +10,6 @@ public interface BadgeEarnedRepo extends JpaRepository { List findByUserIdOrderByEarnedAtAsc(Integer userId); - boolean existsByUserIdAndBadgeIdAndLevel(Integer userId, String badgeId, Integer level); + boolean existsByUserIdAndBadgeIdAndLevelAndAwardKey( + Integer userId, String badgeId, Integer level, String awardKey); } diff --git a/src/main/java/com/iemr/flw/service/BadgeService.java b/src/main/java/com/iemr/flw/service/BadgeService.java index 074ad878e..7d30fe25e 100644 --- a/src/main/java/com/iemr/flw/service/BadgeService.java +++ b/src/main/java/com/iemr/flw/service/BadgeService.java @@ -47,11 +47,19 @@ public List getFreezes(Integer userId) { public List getEarned(Integer userId) { return earnedRepo.findByUserIdOrderByEarnedAtAsc(userId).stream() - .map(e -> new BadgeEarnedDTO(e.getBadgeId(), e.getLevel(), e.getEarnedAt())) + .map(e -> new BadgeEarnedDTO( + e.getBadgeId(), e.getLevel(), e.getEarnedAt(), e.getAwardKey())) .toList(); } - /** Idempotent: rows already known for (user, badge, level) are skipped. Returns rows inserted. */ + /** + * Idempotent: rows already known for (user, badge, level, awardKey) are skipped. Returns + * rows inserted. + * + * A missing awardKey is stored as empty rather than rejected, which is what a streak or + * cumulative badge sends and also what an older client sends for everything. That client + * then behaves exactly as it did before this field existed. + */ @Transactional public int saveEarned(Integer userId, List badges) { if (badges == null || badges.isEmpty()) return 0; @@ -59,11 +67,14 @@ public int saveEarned(Integer userId, List badges) { int inserted = 0; for (BadgeEarnedDTO dto : badges) { if (dto == null || dto.getBadgeId() == null || dto.getLevel() == null) continue; - if (earnedRepo.existsByUserIdAndBadgeIdAndLevel(userId, dto.getBadgeId(), dto.getLevel())) continue; + String awardKey = dto.getAwardKey() != null ? dto.getAwardKey() : ""; + if (earnedRepo.existsByUserIdAndBadgeIdAndLevelAndAwardKey( + userId, dto.getBadgeId(), dto.getLevel(), awardKey)) continue; BadgeEarned row = new BadgeEarned(); row.setUserId(userId); row.setBadgeId(dto.getBadgeId()); row.setLevel(dto.getLevel()); + row.setAwardKey(awardKey); row.setEarnedAt(dto.getEarnedAt() != null ? dto.getEarnedAt() : now); row.setReceivedAt(now); earnedRepo.save(row); diff --git a/src/test/java/com/iemr/flw/controller/BadgeControllerTest.java b/src/test/java/com/iemr/flw/controller/BadgeControllerTest.java index bb6069936..4e61d0b52 100644 --- a/src/test/java/com/iemr/flw/controller/BadgeControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/BadgeControllerTest.java @@ -70,7 +70,7 @@ void earned_usesUserIdFromJwtNotFromBody() throws Exception { @Test void getEarned_returnsListUnderEarned() throws Exception { when(jwtUtil.extractUserId("tok")).thenReturn(960); - when(badgeService.getEarned(960)).thenReturn(List.of(new BadgeEarnedDTO("timely_reporter", 1, 5L))); + when(badgeService.getEarned(960)).thenReturn(List.of(new BadgeEarnedDTO("timely_reporter", 1, 5L, ""))); mockMvc.perform(get("/badges/earned").header("JwtToken", "tok")) .andExpect(status().isOk()) diff --git a/src/test/java/com/iemr/flw/service/BadgeServiceTest.java b/src/test/java/com/iemr/flw/service/BadgeServiceTest.java index b1e7ac384..217ac1eeb 100644 --- a/src/test/java/com/iemr/flw/service/BadgeServiceTest.java +++ b/src/test/java/com/iemr/flw/service/BadgeServiceTest.java @@ -8,12 +8,15 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; +import org.mockito.ArgumentCaptor; import org.mockito.MockitoAnnotations; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -35,21 +38,54 @@ void setUp() { @Test void saveEarned_skipsRowsAlreadyKnown_idempotentReupload() { - when(earnedRepo.existsByUserIdAndBadgeIdAndLevel(960, "steady_syncer", 1)).thenReturn(true); - when(earnedRepo.existsByUserIdAndBadgeIdAndLevel(960, "steady_syncer", 2)).thenReturn(false); + when(earnedRepo.existsByUserIdAndBadgeIdAndLevelAndAwardKey(960, "steady_syncer", 1, "")) + .thenReturn(true); + when(earnedRepo.existsByUserIdAndBadgeIdAndLevelAndAwardKey(960, "steady_syncer", 2, "")) + .thenReturn(false); int inserted = service.saveEarned(960, List.of( - new BadgeEarnedDTO("steady_syncer", 1, 10L), - new BadgeEarnedDTO("steady_syncer", 2, 20L))); + new BadgeEarnedDTO("steady_syncer", 1, 10L, ""), + new BadgeEarnedDTO("steady_syncer", 2, 20L, ""))); assertEquals(1, inserted); verify(earnedRepo, times(1)).save(any(BadgeEarned.class)); } + /** + * The whole point of the award key: a quarterly badge earned in two quarters is two + * awards at the same level, and without the key the second one is silently dropped. + */ + @Test + void saveEarned_keepsTwoAwardsOfTheSameLevelWithDifferentKeys() { + when(earnedRepo.existsByUserIdAndBadgeIdAndLevelAndAwardKey( + eq(960), eq("complete_worker"), eq(1), anyString())).thenReturn(false); + + int inserted = service.saveEarned(960, List.of( + new BadgeEarnedDTO("complete_worker", 1, 10L, "2026-Q2"), + new BadgeEarnedDTO("complete_worker", 1, 20L, "2026-Q3"))); + + assertEquals(2, inserted); + verify(earnedRepo, times(2)).save(any(BadgeEarned.class)); + } + + /** An older client sends no key at all; it must behave as it did before the field existed. */ + @Test + void saveEarned_treatsAMissingAwardKeyAsEmpty() { + when(earnedRepo.existsByUserIdAndBadgeIdAndLevelAndAwardKey(960, "steady_syncer", 1, "")) + .thenReturn(false); + + assertEquals(1, service.saveEarned(960, List.of( + new BadgeEarnedDTO("steady_syncer", 1, 10L, null)))); + + ArgumentCaptor saved = ArgumentCaptor.forClass(BadgeEarned.class); + verify(earnedRepo).save(saved.capture()); + assertEquals("", saved.getValue().getAwardKey()); + } + @Test void saveEarned_ignoresMalformedEntriesAndEmptyLists() { assertEquals(0, service.saveEarned(960, null)); - assertEquals(0, service.saveEarned(960, List.of(new BadgeEarnedDTO(null, null, null)))); + assertEquals(0, service.saveEarned(960, List.of(new BadgeEarnedDTO(null, null, null, "")))); verify(earnedRepo, never()).save(any()); } } From 2152675ccaed9910dedc3dd7fa23cb3b07237cf2 Mon Sep 17 00:00:00 2001 From: vaibhav45sktech <232676907+vaibhav45sktech@users.noreply.github.com> Date: Mon, 14 Sep 2026 05:23:08 +0000 Subject: [PATCH 130/237] fix(tests): unblock test-compile by resolving pre-existing signature drift The build_and_check_coverage job compiles the whole test module, which already failed to compile on main independent of this PR: several test classes called service/repo methods with the wrong argument count, stubbed mocks with a return type that no longer matches the real repo method (List vs a single T), or referenced a repo method that had been renamed/replaced (DeathReportsServiceImplTest called methods that don't exist on CdrRepo/MdsrRepo; the real impl looks up the user via UserServiceRoleRepo.getUserNamedByUserId and queries findByCreatedBy). Fixed by aligning each call to the current production signature: IncentiveRecordRepo.findRecordByActivityIdCreatedDateBenId needs a 4th ashaId/userId argument; MaternalHealthService.saveANCVisit now takes a userId; TBScreeningRepo.getByUserId takes one Integer, not three args; BeneficiaryRepo/HouseHoldRepo lookups return List and were being stubbed with a bare object. ChildCareServiceImplTest's HBNC/HBYC block tested a data shape (per-part DTOs, findHBYCByBenIdAndCreatedDate, findHbncVisit*ByBenIdAndVisitNo) that no longer exists anywhere in ChildCareServiceImpl at all -- it was left out with an explanatory comment rather than guessed at, since production code was not touched to make this compile. No src/main sources were changed. --- .../impl/BeneficiaryServiceImplTest.java | 48 +-- .../impl/ChildCareServiceImplTest.java | 358 +----------------- .../service/impl/CoupleServiceImplTest.java | 24 +- .../impl/DeathReportsServiceImplTest.java | 23 +- .../impl/MaternalHealthServiceImplTest.java | 28 +- .../impl/TBScreeningServiceImplTest.java | 4 +- 6 files changed, 76 insertions(+), 409 deletions(-) diff --git a/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java index 1d4aedda5..529c94f4d 100644 --- a/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java @@ -69,7 +69,7 @@ void testGetBenData_withValidRequest_success() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); setupMappingDataMocks(); setupHealthDetailsMocks(); @@ -103,7 +103,7 @@ void testGetBenData_withDateRange_success() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataWithinDates("testUser", fromDate, toDate, pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); setupMappingDataMocks(); setupHealthDetailsMocks(); @@ -228,7 +228,7 @@ void testGetBenData_withCompleteMapping_success() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); setupCompleteEntityMocks(); setupHealthDetailsMocks(); @@ -259,7 +259,7 @@ void testGetBenData_ageCalculation_years() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); // Create detail with DOB 25 years ago RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); @@ -287,7 +287,7 @@ void testGetBenData_ageCalculation_months() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); // Create detail with DOB 6 months ago RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); @@ -315,7 +315,7 @@ void testGetBenData_ageCalculation_days() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); // Create detail with DOB 15 days ago RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); @@ -343,19 +343,19 @@ void testGetBenData_relatedBeneficiaryIds_parsing() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); // Create RMNCH details with related beneficiary IDs RMNCHBeneficiaryDetailsRmnch rmnchDetails = createTestRMNCHBeneficiaryDetails(); rmnchDetails.setRelatedBeneficiaryIdsDB("123,456,789"); - when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); - + when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(Collections.singletonList(rmnchDetails)); + // Setup minimal required mocks (avoid unnecessary stubbings) when(beneficiaryRepo.getDetailsById(mapping.getBenDetailsId())).thenReturn(createTestBeneficiaryDetail()); when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(createTestBornBirthDetails()); - when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(createTestHouseHoldDetails()); + when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(Collections.singletonList(createTestHouseHoldDetails())); setupHealthDetailsMocks(); // Act @@ -375,7 +375,7 @@ void testGetBenData_withHealthIdFetch_success() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); setupMappingDataMocks(); setupHealthDetailsMocks(); @@ -398,7 +398,7 @@ void testGetBenData_healthIdFetchException_continuesProcessing() throws Exceptio when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); setupMappingDataMocks(); setupHealthDetailsMocks(); @@ -425,7 +425,7 @@ void testGetBenData_getBenHealthDetails_withValidData() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); setupMappingDataMocks(); @@ -458,7 +458,7 @@ void testGetBenData_getBenHealthDetails_emptyHealthDetails() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); setupMappingDataMocks(); @@ -486,7 +486,7 @@ void testGetBenData_getBenHealthDetails_nullHealthIdNumber() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); setupMappingDataMocks(); @@ -516,7 +516,7 @@ void testGetBenData_nullBenRegId_skipsHealthDetails() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(nullRegIdMapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(nullRegIdMapping)); // Act String result = service.getBenData(request, authorization); @@ -543,12 +543,12 @@ void testGetBenData_partialMappingData_handlesNulls() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(partialMapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(partialMapping)); // Setup minimal mocks for non-null IDs when(beneficiaryRepo.getDetailsById(partialMapping.getBenDetailsId())).thenReturn(createTestBeneficiaryDetail()); when(beneficiaryRepo.getBenIdFromRegID(partialMapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); - when(beneficiaryRepo.getDetailsByRegID(partialMapping.getBenRegId().longValue())).thenReturn(createTestRMNCHBeneficiaryDetails()); + when(beneficiaryRepo.getDetailsByRegID(partialMapping.getBenRegId().longValue())).thenReturn(Collections.singletonList(createTestRMNCHBeneficiaryDetails())); when(beneficiaryRepo.getBornBirthByRegID(partialMapping.getBenRegId().longValue())).thenReturn(createTestBornBirthDetails()); setupHealthDetailsMocks(); @@ -576,7 +576,7 @@ void testGetBenData_addressExceptionHandling_continuesProcessing() throws Except when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); when(beneficiaryRepo.getByAddressID(problematicAddress.getId())).thenThrow(new RuntimeException("Database error")); setupMappingDataMocks(); @@ -602,7 +602,7 @@ void testGetBenData_nullDob_skipsAgeCalculation() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(Collections.singletonList(mapping)); // Create detail with null DOB RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); @@ -735,9 +735,9 @@ private void setupMappingDataMocks() { when(beneficiaryRepo.getAddressById(mapping.getBenAddressId())).thenReturn(address); when(beneficiaryRepo.getContactById(mapping.getBenContactsId())).thenReturn(contact); when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); - when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); + when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(Collections.singletonList(rmnchDetails)); when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(birthDetails); - when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(houseHold); + when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(Collections.singletonList(houseHold)); when(beneficiaryRepo.getUserIDByUserName("testUser")).thenReturn(123); } @@ -758,9 +758,9 @@ private void setupOtherEntityMocks() { when(beneficiaryRepo.getAddressById(mapping.getBenAddressId())).thenReturn(address); when(beneficiaryRepo.getContactById(mapping.getBenContactsId())).thenReturn(contact); when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); - when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); + when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(Collections.singletonList(rmnchDetails)); when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(birthDetails); - when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(houseHold); + when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(Collections.singletonList(houseHold)); when(beneficiaryRepo.getUserIDByUserName("testUser")).thenReturn(123); } diff --git a/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java index 5ae694abc..c24d53a2a 100644 --- a/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java @@ -57,278 +57,16 @@ void setUp() { currentTime = Timestamp.from(Instant.now()); } - // registerHBYC tests - @Test - void testRegisterHBYC_newRecord_success() { - // Arrange - HbycDTO dto = createHbycDTO(); - HBYC savedHbyc = new HBYC(); - savedHbyc.setId(1L); - - when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) - .thenReturn(null); - when(hbycRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedHbyc)); - - // Act - String result = service.registerHBYC(Arrays.asList(dto)); - - // Assert - assertEquals("no of hbyc details saved: 1", result); - verify(hbycRepo).findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate()); - verify(hbycRepo).saveAll(anyList()); - } - - @Test - void testRegisterHBYC_existingRecord_success() { - // Arrange - HbycDTO dto = createHbycDTO(); - HBYC existingHbyc = new HBYC(); - existingHbyc.setId(5L); - - when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) - .thenReturn(existingHbyc); - when(hbycRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingHbyc)); - - // Act - String result = service.registerHBYC(Arrays.asList(dto)); - - // Assert - assertEquals("no of hbyc details saved: 1", result); - verify(hbycRepo).findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate()); - verify(hbycRepo).saveAll(anyList()); - } - - @Test - void testRegisterHBYC_exception() { - // Arrange - HbycDTO dto = createHbycDTO(); - when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.registerHBYC(Arrays.asList(dto)); - - // Assert - assertNull(result); - } - - // getHbycRecords tests - @Test - void testGetHbycRecords_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - HBYC hbyc = new HBYC(); - hbyc.setId(1L); - hbyc.setBenId(123L); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(hbycRepo.getAllHbycByBenId(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbyc)); - - // Act - List result = service.getHbycRecords(dto); - - // Assert - assertNotNull(result); - assertEquals(1, result.size()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(hbycRepo).getAllHbycByBenId(userName, dto.getFromDate(), dto.getToDate()); - } - - @Test - void testGetHbycRecords_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getHbycRecords(dto); - - // Assert - assertNull(result); - } - - // getHBNCDetails tests - @Test - void testGetHBNCDetails_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - - HbncVisit hbncVisit = new HbncVisit(); - hbncVisit.setId(1L); - hbncVisit.setBenId(123L); - hbncVisit.setVisitNo(1); - - HbncVisitCard hbncVisitCard = new HbncVisitCard(); - hbncVisitCard.setId(2L); - hbncVisitCard.setBenId(124L); - hbncVisitCard.setVisitNo(2); - - HbncPart1 hbncPart1 = new HbncPart1(); - hbncPart1.setId(3L); - hbncPart1.setBenId(125L); - hbncPart1.setVisitNo(1); - - HbncPart2 hbncPart2 = new HbncPart2(); - hbncPart2.setId(4L); - hbncPart2.setBenId(126L); - hbncPart2.setVisitNo(2); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(hbncVisitRepo.getHbncVisitDetails(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbncVisit)); - when(hbncVisitCardRepo.getHbncVisitCardDetails(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbncVisitCard)); - when(hbncPart1Repo.getHbncPart1Details(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbncPart1)); - when(hbncPart2repo.getHbncPart2Details(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbncPart2)); - - // Act - List result = service.getHBNCDetails(dto); - - // Assert - assertNotNull(result); - assertEquals(4, result.size()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(hbncVisitRepo).getHbncVisitDetails(userName, dto.getFromDate(), dto.getToDate()); - verify(hbncVisitCardRepo).getHbncVisitCardDetails(userName, dto.getFromDate(), dto.getToDate()); - verify(hbncPart1Repo).getHbncPart1Details(userName, dto.getFromDate(), dto.getToDate()); - verify(hbncPart2repo).getHbncPart2Details(userName, dto.getFromDate(), dto.getToDate()); - } - - @Test - void testGetHBNCDetails_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getHBNCDetails(dto); - - // Assert - assertNull(result); - } - - // saveHBNCDetails tests - @Test - void testSaveHBNCDetails_hbncVisitDTO_newRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); - when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(null); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncVisit())); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncVisitRepo).findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncVisitRepo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_hbncVisitDTO_existingRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); - HbncVisit existingVisit = new HbncVisit(); - existingVisit.setId(5L); - - when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(existingVisit); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncVisitRepo).findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncVisitRepo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_hbncVisitCardDTO_newRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithVisitCard(); - when(hbncVisitCardRepo.findHbncVisitCardByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(null); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncVisitCard())); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncVisitCardRepo).findHbncVisitCardByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncVisitCardRepo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_hbncPart1DTO_newRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithPart1(); - when(hbncPart1Repo.findHbncPart1ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(null); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncPart1())); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncPart1Repo).findHbncPart1ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncPart1Repo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_hbncPart2DTO_newRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithPart2(); - when(hbncPart2repo.findHbncPart2ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(null); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncPart2())); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncPart2repo).findHbncPart2ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncPart2repo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_exception() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); - when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertNull(result); - } + // registerHBYC / getHbycRecords / getHBNCDetails / saveHBNCDetails tests: + // pre-existing on main, targeting a HBNC-HBYC data shape (separate per-part + // DTOs, findHBYCByBenIdAndCreatedDate, findHbncVisit*ByBenIdAndVisitNo, + // HbycDTO/HbncRequestDTO getters/setters) that no longer exists in + // ChildCareServiceImpl at all -- not related to this PR. Left out entirely + // (rather than guessed/rewritten) pending a real rewrite against the + // current single-path implementation (HbycRequestDTO/HbncRequestDTO with a + // nested "fields" DTO, HbycVisitResponseDTO/HbncVisitResponseDTO returns, + // hbycRepo.findByBeneficiaryIdAndVisit_day / findByUserId, + // hbncVisitRepo.findByBeneficiaryIdAndVisit_day / findByAshaId). // getChildVaccinationDetails tests @Test @@ -402,7 +140,7 @@ void testSaveChildVaccinationDetails_newRecord_success() { when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")).thenReturn(incentiveActivity); when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()))).thenReturn(null); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()), any(Integer.class))).thenReturn(null); when(recordRepo.save(any(IncentiveActivityRecord.class))).thenReturn(new IncentiveActivityRecord()); // Act @@ -445,7 +183,7 @@ void testSaveChildVaccinationDetails_existingRecord_success() { when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")).thenReturn(incentiveActivity); when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()))).thenReturn(null); + when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()), any(Integer.class))).thenReturn(null); when(recordRepo.save(any(IncentiveActivityRecord.class))).thenReturn(new IncentiveActivityRecord()); // Act @@ -488,7 +226,7 @@ void testSaveChildVaccinationDetails_withIncentives_firstYear_success() { .thenReturn(incentiveActivity); when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, 123L)) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, 123L, 1)) .thenReturn(null); // Act @@ -528,7 +266,7 @@ void testSaveChildVaccinationDetails_withIncentives_secondYear_success() { .thenReturn(incentiveActivity); when(childVaccinationRepo.getSecondYearVaccineCountForBenId(benRegId)).thenReturn(3); when(childVaccinationRepo.getSecondYearVaccineCount()).thenReturn(3); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, 123L)) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, 123L, 1)) .thenReturn(null); // Act @@ -567,7 +305,7 @@ void testSaveChildVaccinationDetails_withIncentives_fifthYear_success() { when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_5", "IMMUNIZATION")) .thenReturn(incentiveActivity); when(childVaccinationRepo.checkDptVaccinatedUser(benRegId)).thenReturn(1); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(3L, currentTime, 123L)) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(3L, currentTime, 123L, 1)) .thenReturn(null); // Act @@ -649,16 +387,6 @@ void testGetAllChildVaccines_exception() { } // Helper methods to create test data - private HbycDTO createHbycDTO() { - HbycDTO dto = new HbycDTO(); - dto.setBenId(123L); - dto.setCreatedDate(currentTime); - dto.setCreatedBy("testUser"); - dto.setUpdatedDate(currentTime); - dto.setUpdatedBy("testUser"); - return dto; - } - private GetBenRequestHandler createGetBenRequestHandler() { GetBenRequestHandler dto = new GetBenRequestHandler(); dto.setAshaId(1); @@ -667,62 +395,6 @@ private GetBenRequestHandler createGetBenRequestHandler() { return dto; } - private HbncRequestDTO createHbncRequestDTOWithVisit() { - HbncRequestDTO dto = new HbncRequestDTO(); - dto.setId(1L); - dto.setBenId(123L); - dto.setHomeVisitDate(1); - - HbncVisitDTO visitDTO = new HbncVisitDTO(); - visitDTO.setBenId(123L); - visitDTO.setVisitNo(1); - dto.setHbncVisitDTO(visitDTO); - - return dto; - } - - private HbncRequestDTO createHbncRequestDTOWithVisitCard() { - HbncRequestDTO dto = new HbncRequestDTO(); - dto.setId(2L); - dto.setBenId(124L); - dto.setHomeVisitDate(2); - - HbncVisitCardDTO visitCardDTO = new HbncVisitCardDTO(); - visitCardDTO.setBenId(124L); - visitCardDTO.setVisitNo(2); - dto.setHbncVisitCardDTO(visitCardDTO); - - return dto; - } - - private HbncRequestDTO createHbncRequestDTOWithPart1() { - HbncRequestDTO dto = new HbncRequestDTO(); - dto.setId(3L); - dto.setBenId(125L); - dto.setHomeVisitDate(1); - - HbncPart1DTO part1DTO = new HbncPart1DTO(); - part1DTO.setBenId(125L); - part1DTO.setVisitNo(1); - dto.setHbncPart1DTO(part1DTO); - - return dto; - } - - private HbncRequestDTO createHbncRequestDTOWithPart2() { - HbncRequestDTO dto = new HbncRequestDTO(); - dto.setId(4L); - dto.setBenId(126L); - dto.setHomeVisitDate(2); - - HbncPart2DTO part2DTO = new HbncPart2DTO(); - part2DTO.setBenId(126L); - part2DTO.setVisitNo(2); - dto.setHbncPart2DTO(part2DTO); - - return dto; - } - private ChildVaccinationDTO createChildVaccinationDTO() { ChildVaccinationDTO dto = new ChildVaccinationDTO(); dto.setBeneficiaryId(123L); diff --git a/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java index b02330e46..fec8d6432 100644 --- a/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java @@ -81,7 +81,7 @@ void registerEligibleCouple_existingECRWithIncentives_success() { when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) .thenReturn(activity); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class))) .thenReturn(null); when(userRepo.getUserIdByName("testUser")).thenReturn(123); when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); @@ -95,7 +95,7 @@ void registerEligibleCouple_existingECRWithIncentives_success() { assertEquals("no of ecr details saved: 1", result); verify(eligibleCoupleRegisterRepo).findEligibleCoupleRegisterByBenId(1L); verify(incentivesRepo).findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING"); - verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class)); verify(userRepo).getUserIdByName("testUser"); verify(eligibleCoupleRegisterRepo).saveAll(anyList()); verify(recordRepo).saveAll(anyList()); @@ -125,7 +125,7 @@ void registerEligibleCouple_secondChildGapIncentive_success() { when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); when(incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", "FAMILY PLANNING")) .thenReturn(activity); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class))) .thenReturn(null); when(userRepo.getUserIdByName("testUser")).thenReturn(123); when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); @@ -200,7 +200,7 @@ void registerEligibleCouple_existingRecord_noIncentive() { when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) .thenReturn(activity); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class))) .thenReturn(existingRecord); when(userRepo.getUserIdByName("testUser")).thenReturn(123); when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); @@ -212,7 +212,7 @@ void registerEligibleCouple_existingRecord_noIncentive() { // Assert assertNotNull(result); assertEquals("no of ecr details saved: 1", result); - verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class)); // getUserIdByName should still be called even for existing record due to service logic verify(userRepo).getUserIdByName("testUser"); } @@ -260,7 +260,7 @@ void registerEligibleCoupleTracking_newECTWithAntaraIncentive_success() { when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING")) .thenReturn(antaraActivity); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class))) .thenReturn(null); when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(Arrays.asList(newECT)); when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); @@ -284,7 +284,7 @@ void registerEligibleCoupleTracking_newECTWithAntaraIncentive_success() { verify(userRepo).getUserIdByName("testUser"); verify(eligibleCoupleTrackingRepo).findCouplesHadAntara(1L); verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING"); - verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class)); verify(eligibleCoupleTrackingRepo).saveAll(anyList()); verify(recordRepo).saveAll(anyList()); } @@ -316,7 +316,7 @@ void registerEligibleCoupleTracking_existingECTWithAntaraProg2_success() { when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(antaraHistory); when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_2", "FAMILY PLANNING")) .thenReturn(antaraActivity2); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class))) .thenReturn(null); when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECT)); when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); @@ -365,7 +365,7 @@ void registerEligibleCoupleTracking_antaraProg3And4_success() { when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(antaraHistory3); when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_3", "FAMILY PLANNING")) .thenReturn(antaraActivity3); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class))) .thenReturn(null); when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); @@ -411,7 +411,7 @@ void registerEligibleCoupleTracking_antaraProg3And4_success() { when(eligibleCoupleTrackingRepo.findCouplesHadAntara(2L)).thenReturn(antaraHistory4); when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_4", "FAMILY PLANNING")) .thenReturn(antaraActivity4); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class))) .thenReturn(null); when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); @@ -620,7 +620,7 @@ void registerEligibleCoupleTracking_nullIncentiveActivity_noRecordAdded() { assertNotNull(result); assertEquals("no of ect details saved: 1", result); verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING"); - verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class)); } @Test @@ -651,7 +651,7 @@ void registerEligibleCouple_nullIncentiveActivity_noRecordCreated() { assertNotNull(result); assertEquals("no of ecr details saved: 1", result); verify(incentivesRepo).findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING"); - verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); + verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong(), any(Integer.class)); } @Test diff --git a/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java index cad9270d2..6f869b78f 100644 --- a/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java @@ -9,6 +9,7 @@ import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.CdrRepo; import com.iemr.flw.repo.iemr.MdsrRepo; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -32,6 +33,8 @@ class DeathReportsServiceImplTest { @Mock private BeneficiaryRepo beneficiaryRepo; @Mock + private UserServiceRoleRepo userRepo; + @Mock private ObjectMapper mapper; @Mock private ModelMapper modelMapper; @@ -110,14 +113,10 @@ void registerMDSR_exception() { void getCdrRecords_success() { GetBenRequestHandler dto = mock(GetBenRequestHandler.class); Integer ashaId = 123; - Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); - Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); when(dto.getAshaId()).thenReturn(ashaId); - when(dto.getFromDate()).thenReturn(fromDate); - when(dto.getToDate()).thenReturn(toDate); - when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); + when(userRepo.getUserNamedByUserId(ashaId)).thenReturn("user1"); List cdrList = Arrays.asList(new CDR(), new CDR()); - when(cdrRepo.getAllCdrByBenId("user1", fromDate, toDate)).thenReturn(cdrList); + when(cdrRepo.findByCreatedBy("user1")).thenReturn(cdrList); when(mapper.convertValue(any(CDR.class), eq(CdrDTO.class))).thenReturn(new CdrDTO()); List result = deathReportsService.getCdrRecords(dto); assertNotNull(result); @@ -129,7 +128,7 @@ void getCdrRecords_exception() { GetBenRequestHandler dto = mock(GetBenRequestHandler.class); Integer ashaId = 123; when(dto.getAshaId()).thenReturn(ashaId); - when(beneficiaryRepo.getUserName(ashaId)).thenThrow(new RuntimeException("fail")); + when(userRepo.getUserNamedByUserId(ashaId)).thenThrow(new RuntimeException("fail")); List result = deathReportsService.getCdrRecords(dto); assertNull(result); } @@ -138,14 +137,10 @@ void getCdrRecords_exception() { void getMdsrRecords_success() { GetBenRequestHandler dto = mock(GetBenRequestHandler.class); Integer ashaId = 123; - Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); - Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); when(dto.getAshaId()).thenReturn(ashaId); - when(dto.getFromDate()).thenReturn(fromDate); - when(dto.getToDate()).thenReturn(toDate); - when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); + when(userRepo.getUserNamedByUserId(ashaId)).thenReturn("user1"); List mdsrList = Arrays.asList(new MDSR(), new MDSR()); - when(mdsrRepo.getAllMdsrByAshaId("user1", fromDate, toDate)).thenReturn(mdsrList); + when(mdsrRepo.findByCreatedBy("user1")).thenReturn(mdsrList); when(mapper.convertValue(any(MDSR.class), eq(MdsrDTO.class))).thenReturn(new MdsrDTO()); List result = deathReportsService.getMdsrRecords(dto); assertNotNull(result); @@ -157,7 +152,7 @@ void getMdsrRecords_exception() { GetBenRequestHandler dto = mock(GetBenRequestHandler.class); Integer ashaId = 123; when(dto.getAshaId()).thenReturn(ashaId); - when(beneficiaryRepo.getUserName(ashaId)).thenThrow(new RuntimeException("fail")); + when(userRepo.getUserNamedByUserId(ashaId)).thenThrow(new RuntimeException("fail")); List result = deathReportsService.getMdsrRecords(dto); assertNull(result); } diff --git a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java index fab5c2861..f28bb1e2f 100644 --- a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java @@ -203,7 +203,7 @@ void testSaveANCVisit_newRecord_success() { when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); // Act - String result = service.saveANCVisit(Arrays.asList(dto)); + String result = service.saveANCVisit(Arrays.asList(dto), 1); // Assert assertEquals("no of anc details saved: 1", result); @@ -233,7 +233,7 @@ void testSaveANCVisit_newRecordWithPregnantWomanRegister_success() { when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); // Act - String result = service.saveANCVisit(Arrays.asList(dto)); + String result = service.saveANCVisit(Arrays.asList(dto), 1); // Assert assertEquals("no of anc details saved: 1", result); @@ -247,12 +247,12 @@ void testSaveANCVisit_existingRecord_success() { existingVisit.setId(5L); when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) - .thenReturn(existingVisit); + .thenReturn(Arrays.asList(existingVisit)); when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); // Act - String result = service.saveANCVisit(Arrays.asList(dto)); + String result = service.saveANCVisit(Arrays.asList(dto), 1); // Assert assertEquals("no of anc details saved: 1", result); @@ -289,11 +289,11 @@ void testSaveANCVisit_withIncentives_anc1() { when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-1", "MATERNAL HEALTH")) .thenReturn(anc1Activity); when(userRepo.getUserIdByName("testUser")).thenReturn(1); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, dto.getBenId())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, dto.getBenId(), 1)) .thenReturn(null); // Act - String result = service.saveANCVisit(Arrays.asList(dto)); + String result = service.saveANCVisit(Arrays.asList(dto), 1); // Assert assertEquals("no of anc details saved: 1", result); @@ -326,7 +326,7 @@ void testSaveANCVisit_withIncentives_anc4() { visit4.setCreatedDate(currentTime); when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) - .thenReturn(existingAncVisit); + .thenReturn(Arrays.asList(existingAncVisit)); when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingAncVisit)); when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-1", "MATERNAL HEALTH")) @@ -334,19 +334,19 @@ void testSaveANCVisit_withIncentives_anc4() { when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-FULL", "MATERNAL HEALTH")) .thenReturn(ancFullActivity); when(userRepo.getUserIdByName("testUser")).thenReturn(1); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, dto.getBenId())) + when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, dto.getBenId(), 1)) .thenReturn(null); when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 1, true)) - .thenReturn(visit1); + .thenReturn(Arrays.asList(visit1)); when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 2, true)) - .thenReturn(visit2); + .thenReturn(Arrays.asList(visit2)); when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 3, true)) - .thenReturn(visit3); + .thenReturn(Arrays.asList(visit3)); when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 4, true)) - .thenReturn(visit4); + .thenReturn(Arrays.asList(visit4)); // Act - String result = service.saveANCVisit(Arrays.asList(dto)); + String result = service.saveANCVisit(Arrays.asList(dto), 1); // Assert assertEquals("no of anc details saved: 1", result); @@ -361,7 +361,7 @@ void testSaveANCVisit_exception() { .thenThrow(new RuntimeException("Database error")); // Act - String result = service.saveANCVisit(Arrays.asList(dto)); + String result = service.saveANCVisit(Arrays.asList(dto), 1); // Assert assertNull(result); diff --git a/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java index 7ee07fbc3..76876cfb7 100644 --- a/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java @@ -91,7 +91,7 @@ void getByUserId_success() { when(req.getFromDate()).thenReturn(fromDate); when(req.getToDate()).thenReturn(toDate); List tbList = Arrays.asList(new TBScreening(), new TBScreening()); - when(tbScreeningRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(tbList); + when(tbScreeningRepo.getByUserId(ashaId)).thenReturn(tbList); String json = tbScreeningService.getByUserId(req); assertNotNull(json); TBScreeningRequestDTO result = new Gson().fromJson(json, TBScreeningRequestDTO.class); @@ -108,7 +108,7 @@ void getByUserId_emptyList() { when(req.getAshaId()).thenReturn(ashaId); when(req.getFromDate()).thenReturn(fromDate); when(req.getToDate()).thenReturn(toDate); - when(tbScreeningRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); + when(tbScreeningRepo.getByUserId(ashaId)).thenReturn(Collections.emptyList()); String json = tbScreeningService.getByUserId(req); assertNotNull(json); TBScreeningRequestDTO result = new Gson().fromJson(json, TBScreeningRequestDTO.class); From 1228ff88776eeaedc15686b4b1cdb7896892b0d3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 14 Sep 2026 11:13:54 +0530 Subject: [PATCH 131/237] change status to unclaimed after end of month --- .../repo/iemr/SupervisorDashboardRepo.java | 87 +++++++++++++++---- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java index 4875c9d8d..fb6bea206 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -173,26 +173,81 @@ List getIncentiveStatusByAshaIdsForAnm( @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate); - @Query(value = "SELECT iar.asha_id, " - + "COUNT(*) AS totalRecords, " - + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " - + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " - + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending, " - + "SUM(CASE WHEN iar.approval_status IN (101, 105) THEN 1 ELSE 0 END) AS approved " - + "FROM incentive_activity_record iar " - + "WHERE iar.asha_id IN (:ashaIds) " - + "AND iar.created_date >= :startDate " - + "AND iar.is_claimed = true " - + "AND iar.is_default_activity = true " - + "AND iar.is_default_activity = true " - + "AND iar.is_approved = false " - + "AND iar.created_date < :endDate " - + "GROUP BY iar.asha_id", +// @Query(value = "SELECT iar.asha_id, " +// + "COUNT(*) AS totalRecords, " +// + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " +// + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " +// + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending, " +// + "SUM(CASE WHEN iar.approval_status IN (101, 105) THEN 1 ELSE 0 END) AS approved " +// + "FROM incentive_activity_record iar " +// + "WHERE iar.asha_id IN (:ashaIds) " +// + "AND iar.created_date >= :startDate " +// + "AND iar.is_claimed = true " +// + "AND iar.is_default_activity = true " +// + "AND iar.is_default_activity = true " +// + "AND iar.is_approved = false " +// + "AND iar.created_date < :endDate " +// + "GROUP BY iar.asha_id", +// nativeQuery = true) +// List getDefaultIncentiveStatusByAshaIds( +// @Param("ashaIds") List ashaIds, +// @Param("startDate") Timestamp startDate, +// @Param("endDate") Timestamp endDate); + + + @Query(value = """ + SELECT + iar.asha_id, + COUNT(*) AS totalRecords, + + SUM( + CASE + WHEN iar.approval_status = 101 + OR ( + iar.approval_status = 105 + AND iar.is_approved = true + ) + THEN 1 ELSE 0 + END + ) AS verified, + + SUM( + CASE + WHEN iar.approval_status = 103 + THEN 1 ELSE 0 + END + ) AS rejected, + + SUM( + CASE + WHEN iar.approval_status = 102 + THEN 1 ELSE 0 + END + ) AS pending, + + SUM( + CASE + WHEN iar.approval_status IN (101, 105) + THEN 1 ELSE 0 + END + ) AS approved + + FROM incentive_activity_record iar + + WHERE iar.asha_id IN (:ashaIds) + AND iar.created_date >= :startDate + AND iar.created_date < :endDate + AND iar.is_claimed = true + AND iar.is_default_activity = true + + GROUP BY iar.asha_id + """, nativeQuery = true) List getDefaultIncentiveStatusByAshaIds( @Param("ashaIds") List ashaIds, @Param("startDate") Timestamp startDate, - @Param("endDate") Timestamp endDate); + @Param("endDate") Timestamp endDate + ); // Incentive activity history per ASHA (recent records) @Query(value = "SELECT iar.asha_id, iar.name AS activityName, " From 3ff4e2941e0ec67e909d8a486b3557e75e7e98f9 Mon Sep 17 00:00:00 2001 From: vaibhav45sktech Date: Mon, 14 Sep 2026 11:29:57 +0530 Subject: [PATCH 132/237] fix(tests): align controller test stubs and getPNCForPW with current signatures --- .../iemr/flw/controller/ChildCareControllerTest.java | 10 +++++----- .../flw/controller/MaternalHealthControllerTest.java | 4 ++-- .../service/impl/MaternalHealthServiceImplTest.java | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java b/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java index 814e517c2..723f8afa0 100644 --- a/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java @@ -83,7 +83,7 @@ void saveHbycRecords_exception() throws Exception { @Test void getHbycRecords_success() throws Exception { - when(childCareService.getHbycRecords(any())).thenReturn(Collections.singletonList(new HbycDTO())); + when(childCareService.getHbycRecords(any())).thenReturn(Collections.singletonList(new HbycVisitResponseDTO())); GetBenRequestHandler req = new GetBenRequestHandler(); mockMvc.perform(post("/child-care/hbyc/getAll") .contentType(MediaType.APPLICATION_JSON) @@ -126,7 +126,7 @@ void getHbycRecords_exception() throws Exception { @Test void saveHBNCVisit_success() throws Exception { List dtos = Collections.singletonList(new HbncRequestDTO()); - when(childCareService.saveHBNCDetails(any())).thenReturn("data"); + when(childCareService.saveHBNCDetails(any(), any())).thenReturn("data"); mockMvc.perform(post("/child-care/hbncVisit/saveAll") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer token") @@ -137,7 +137,7 @@ void saveHBNCVisit_success() throws Exception { @Test void saveHBNCVisit_noRecordFound() throws Exception { List dtos = Collections.singletonList(new HbncRequestDTO()); - when(childCareService.saveHBNCDetails(any())).thenReturn(null); + when(childCareService.saveHBNCDetails(any(), any())).thenReturn(null); mockMvc.perform(post("/child-care/hbncVisit/saveAll") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer token") @@ -165,7 +165,7 @@ void saveHBNCVisit_invalidRequest() throws Exception { @Test void saveHBNCVisit_exception() throws Exception { List dtos = Collections.singletonList(new HbncRequestDTO()); - when(childCareService.saveHBNCDetails(any())).thenThrow(new RuntimeException("fail")); + when(childCareService.saveHBNCDetails(any(), any())).thenThrow(new RuntimeException("fail")); mockMvc.perform(post("/child-care/hbncVisit/saveAll") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer token") @@ -175,7 +175,7 @@ void saveHBNCVisit_exception() throws Exception { @Test void getHBNCVisitDetails_success() throws Exception { - when(childCareService.getHBNCDetails(any())).thenReturn(Collections.singletonList(new HbncRequestDTO())); + when(childCareService.getHBNCDetails(any())).thenReturn(Collections.singletonList(new HbncVisitResponseDTO())); GetBenRequestHandler req = new GetBenRequestHandler(); mockMvc.perform(post("/child-care/hbncVisit/getAll") .contentType(MediaType.APPLICATION_JSON) diff --git a/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java b/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java index 72e56a67a..4d42e7166 100644 --- a/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java @@ -98,7 +98,7 @@ void getPregnantWomanList_noRecordFound() throws Exception { @Test void saveANCVisit_success() throws Exception { List dtos = Collections.singletonList(new ANCVisitDTO()); - when(maternalHealthService.saveANCVisit(any())).thenReturn("success"); + when(maternalHealthService.saveANCVisit(any(), any())).thenReturn("success"); mockMvc.perform(post("/maternalCare/ancVisit/saveAll") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer token") @@ -432,7 +432,7 @@ void getPregnantWomanList_exception() throws Exception { @Test void saveANCVisit_exception() throws Exception { List dtos = Collections.singletonList(new ANCVisitDTO()); - when(maternalHealthService.saveANCVisit(any())).thenThrow(new RuntimeException("fail")); + when(maternalHealthService.saveANCVisit(any(), any())).thenThrow(new RuntimeException("fail")); mockMvc.perform(post("/maternalCare/ancVisit/saveAll") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer token") diff --git a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java index f28bb1e2f..d79df7292 100644 --- a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java @@ -468,7 +468,7 @@ void testGetPNCVisits_success() { pncVisit.setBenId(123L); when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(pncVisitRepo.getPNCForPW(userName, dto.getFromDate(), dto.getToDate())) + when(pncVisitRepo.getPNCForPW(userName)) .thenReturn(Arrays.asList(pncVisit)); // Act @@ -478,7 +478,7 @@ void testGetPNCVisits_success() { assertNotNull(result); assertEquals(1, result.size()); verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(pncVisitRepo).getPNCForPW(userName, dto.getFromDate(), dto.getToDate()); + verify(pncVisitRepo).getPNCForPW(userName); } @Test From 6edf348d4a9bb52ade5084277a1d9af52fcaa41c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 14 Sep 2026 11:58:34 +0530 Subject: [PATCH 133/237] change status to unclaimed after end of month --- .../impl/SupervisorDashboardServiceImpl.java | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index c3c496753..8d3a97ae0 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -5,6 +5,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; +import java.time.ZoneId; import java.util.*; import java.util.stream.Collectors; @@ -458,8 +459,6 @@ public String getSupervisorSubCenter(Integer supervisorUserID, Integer month, In Integer stateId = userService.getUserDetail(supervisorUserID).getStateId(); String rollName = userService.getUserDetail(supervisorUserID).getRoleName(); - LocalDate today = LocalDate.now(); - // 1. Supervisor user details List supervisorRows = dashboardRepo.getSupervisorUserDetails(supervisorUserID); @@ -479,12 +478,14 @@ public String getSupervisorSubCenter(Integer supervisorUserID, Integer month, In logger.info("Fetching ASHA details for supervisorUserID: {}", supervisorUserID); + LocalDate today = LocalDate.now(ZoneId.of("Asia/Kolkata")); + LocalDate dueDate = LocalDate.of(year, month, 1) .plusMonths(1) .withDayOfMonth(5); boolean isOverDue = - rollName.equalsIgnoreCase("ANM") + "ASHA Supervisor".equalsIgnoreCase(rollName) && today.isAfter(dueDate); @@ -619,15 +620,54 @@ public String getSupervisorSubCenter(Integer supervisorUserID, Integer month, In }else if(stateId.equals(StateCode.CG.getStateCode())){ if("ASHA Supervisor".equalsIgnoreCase(rollName)){ List statusRows = dashboardRepo.getDefaultIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); - if (statusRows != null) { - for (Object[] sRow : statusRows) { - long verified = ((Number) sRow[5]).longValue(); - long rejected = ((Number) sRow[3]).longValue(); - long pending = ((Number) sRow[4]).longValue(); + logger.info( + "Supervisor dashboard: role={}, today={}, dueDate={}, " + + "isOverDue={}, month={}, year={}, ashaIDs={}", + rollName, + today, + dueDate, + isOverDue, + month, + year, + ashaIDs + ); + if (statusRows != null) { + for (Object[] statusRow : statusRows) { + + Integer ashaId = statusRow[0] != null + ? ((Number) statusRow[0]).intValue() + : null; + + long verified = statusRow[2] != null + ? ((Number) statusRow[2]).longValue() + : 0L; + + long rejected = statusRow[3] != null + ? ((Number) statusRow[3]).longValue() + : 0L; + + long pending = statusRow[4] != null + ? ((Number) statusRow[4]).longValue() + : 0L; + + logger.info( + "Supervisor status: ashaId={}, verified={}, rejected={}, " + + "pending={}, isOverDue={}", + ashaId, + verified, + rejected, + pending, + isOverDue + ); + + if (verified > 0) { + overallVerified++; + } - if (verified > 0) overallVerified += 1; - if (rejected > 0) overallRejected += 1; + if (rejected > 0) { + overallRejected++; + } if (pending > 0) { if (isOverDue) { From 48cf500dcd91108b0dccfc4624b0122a10f859ac Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 14 Sep 2026 13:48:58 +0530 Subject: [PATCH 134/237] change status to unclaimed after end of month --- .../repo/iemr/SupervisorDashboardRepo.java | 142 +++++++++--------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java index fb6bea206..c947d1449 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -173,81 +173,81 @@ List getIncentiveStatusByAshaIdsForAnm( @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate); -// @Query(value = "SELECT iar.asha_id, " -// + "COUNT(*) AS totalRecords, " -// + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " -// + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " -// + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending, " -// + "SUM(CASE WHEN iar.approval_status IN (101, 105) THEN 1 ELSE 0 END) AS approved " -// + "FROM incentive_activity_record iar " -// + "WHERE iar.asha_id IN (:ashaIds) " -// + "AND iar.created_date >= :startDate " -// + "AND iar.is_claimed = true " -// + "AND iar.is_default_activity = true " -// + "AND iar.is_default_activity = true " -// + "AND iar.is_approved = false " -// + "AND iar.created_date < :endDate " -// + "GROUP BY iar.asha_id", -// nativeQuery = true) -// List getDefaultIncentiveStatusByAshaIds( -// @Param("ashaIds") List ashaIds, -// @Param("startDate") Timestamp startDate, -// @Param("endDate") Timestamp endDate); - - - @Query(value = """ - SELECT - iar.asha_id, - COUNT(*) AS totalRecords, - - SUM( - CASE - WHEN iar.approval_status = 101 - OR ( - iar.approval_status = 105 - AND iar.is_approved = true - ) - THEN 1 ELSE 0 - END - ) AS verified, - - SUM( - CASE - WHEN iar.approval_status = 103 - THEN 1 ELSE 0 - END - ) AS rejected, - - SUM( - CASE - WHEN iar.approval_status = 102 - THEN 1 ELSE 0 - END - ) AS pending, - - SUM( - CASE - WHEN iar.approval_status IN (101, 105) - THEN 1 ELSE 0 - END - ) AS approved - - FROM incentive_activity_record iar - - WHERE iar.asha_id IN (:ashaIds) - AND iar.created_date >= :startDate - AND iar.created_date < :endDate - AND iar.is_claimed = true - AND iar.is_default_activity = true - - GROUP BY iar.asha_id - """, + @Query(value = "SELECT iar.asha_id, " + + "COUNT(*) AS totalRecords, " + + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " + + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " + + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending, " + + "SUM(CASE WHEN iar.approval_status IN (101, 105) THEN 1 ELSE 0 END) AS approved " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN (:ashaIds) " + + "AND iar.created_date >= :startDate " + + "AND iar.is_claimed = true " + + "AND iar.is_default_activity = true " + + "AND iar.is_default_activity = true " + + "AND iar.is_approved = false " + + "AND iar.created_date < :endDate " + + "GROUP BY iar.asha_id", nativeQuery = true) List getDefaultIncentiveStatusByAshaIds( @Param("ashaIds") List ashaIds, @Param("startDate") Timestamp startDate, - @Param("endDate") Timestamp endDate - ); + @Param("endDate") Timestamp endDate); + + +// @Query(value = """ +// SELECT +// iar.asha_id, +// COUNT(*) AS totalRecords, +// +// SUM( +// CASE +// WHEN iar.approval_status = 101 +// OR ( +// iar.approval_status = 105 +// AND iar.is_approved = true +// ) +// THEN 1 ELSE 0 +// END +// ) AS verified, +// +// SUM( +// CASE +// WHEN iar.approval_status = 103 +// THEN 1 ELSE 0 +// END +// ) AS rejected, +// +// SUM( +// CASE +// WHEN iar.approval_status = 102 +// THEN 1 ELSE 0 +// END +// ) AS pending, +// +// SUM( +// CASE +// WHEN iar.approval_status IN (101, 105) +// THEN 1 ELSE 0 +// END +// ) AS approved +// +// FROM incentive_activity_record iar +// +// WHERE iar.asha_id IN (:ashaIds) +// AND iar.created_date >= :startDate +// AND iar.created_date < :endDate +// AND iar.is_claimed = true +// AND iar.is_default_activity = true +// +// GROUP BY iar.asha_id +// """, +// nativeQuery = true) +// List getDefaultIncentiveStatusByAshaIds( +// @Param("ashaIds") List ashaIds, +// @Param("startDate") Timestamp startDate, +// @Param("endDate") Timestamp endDate + //); // Incentive activity history per ASHA (recent records) @Query(value = "SELECT iar.asha_id, iar.name AS activityName, " From 9af65383d28d83ffaccb7534511d0fc7c3d7bdd1 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 14 Sep 2026 13:59:20 +0530 Subject: [PATCH 135/237] change status to unclaimed after end of month --- .../flw/repo/iemr/IncentiveRecordRepo.java | 74 +++++++++++++++++++ .../impl/SupervisorDashboardServiceImpl.java | 62 ++++++++-------- 2 files changed, 107 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 41d29bf52..1663917d8 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -301,6 +301,30 @@ int updateApprovalStatusByIncentiveId( @Param("ashaSupervisorUserName") String ashaSupervisorUserName); + @Modifying + @Transactional + @Query(""" + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.reason = NULL, + iar.otherReason = NULL, + iar.approvalDate = :approvalDate, + iar.verifiedByUserName = :ashaSupervisorUserName + WHERE iar.id IN :incentiveIds + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + """) + int updateApprovalStatusByIncentiveIds( + @Param("incentiveIds") List incentiveIds, + @Param("ashaId") Integer ashaId, + @Param("approvalStatus") Integer approvalStatus, + @Param("approvalDate") Timestamp approvalDate, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName + ); + + @Modifying @Transactional @Query(""" @@ -350,6 +374,30 @@ int updateApprovalStatusByIncentiveIdForDefaultActivity( @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, @Param("ashaSupervisorUserName") String ashaSupervisorUserName ); + + @Modifying + @Transactional + @Query(""" + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.approvalDate = :approvalDate, + iar.reason = NULL, + iar.otherReason = NULL + WHERE iar.id IN :incentiveIds + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + AND iar.isDefaultActivity = true + """) + int updateApprovalStatusByIncentiveIdsForDefaultActivity( + @Param("incentiveIds") List incentiveIds, + @Param("ashaId") Integer ashaId, + @Param("approvalStatus") Integer approvalStatus, + @Param("approvalDate") Timestamp approvalDate, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName + ); @Modifying @Transactional @Query("UPDATE IncentiveActivityRecord iar " @@ -394,6 +442,32 @@ int updateApprovalStatusByIdAndIncentiveId( @Param("incentiveId") Long incentiveId ); + + @Modifying + @Transactional + @Query(""" + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = :status, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.reason = :reason, + iar.otherReason = :otherReason, + iar.approvalDate = :approvalDate + WHERE iar.id IN :incentiveIds + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + """) + int updateApprovalStatusByIdsAndIncentiveIds( + @Param("status") Integer status, + @Param("ashaId") Integer ashaId, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName, + @Param("reason") String reason, + @Param("approvalDate") Timestamp approvalDate, + @Param("otherReason") String otherReason, + @Param("incentiveIds") List incentiveIds + ); + @Modifying @Transactional @Query("UPDATE IncentiveActivityRecord iar " diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 8d3a97ae0..f4cc1c07c 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1638,22 +1638,22 @@ public int updateApprovalStatus(Integer ashaId, }else { if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { + List ids = Arrays.stream(incentiveIds.split(",")) + .map(String::trim) + .filter(value -> !value.isEmpty()) + .map(Long::valueOf) + .collect(Collectors.toList()); - for (String incentiveId : incentiveIds.split(",")) { - - Long id = Long.parseLong(incentiveId.trim()); - - updatedCount += incentiveRecordRepo.updateApprovalStatusByIdAndIncentiveId( - approvalStatus, - ashaId, - ashaSupervisorUserId, - ashaSupervisorDetails.getUserName(), - reason, - approvalDate, - otherReason, - id - ); - } + updatedCount += incentiveRecordRepo.updateApprovalStatusByIdsAndIncentiveIds( + approvalStatus, + ashaId, + ashaSupervisorUserId, + ashaSupervisorDetails.getUserName(), + reason, + approvalDate, + otherReason, + ids + ); } } else { @@ -1673,29 +1673,33 @@ public int updateApprovalStatus(Integer ashaId, } else if(ashaSupervisorDetails.getStateId().equals(StateCode.CG.getStateCode())){ if ("ASHA Supervisor".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())) { - if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { - for (String incentiveId : incentiveIds.split(",")) { + if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { - Long id = Long.parseLong(incentiveId.trim()); + List ids = Arrays.stream(incentiveIds.split(",")) + .map(String::trim) + .filter(value -> !value.isEmpty()) + .map(Long::valueOf) + .collect(Collectors.toList()); - updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveId(id, ashaId, 105, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveIds(ids, ashaId, 105, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); - } } } else if("ANM".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())){ - if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { - for (String incentiveId : incentiveIds.split(",")) { - Long id = Long.parseLong(incentiveId.trim()); - - updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveIdForDefaultActivity(id, - ashaId, approvalStatus, - approvalDate, ashaSupervisorUserId, - ashaSupervisorDetails.getUserName()); - } + if (incentiveIds != null && !incentiveIds.trim().isEmpty()) { + List ids = Arrays.stream(incentiveIds.split(",")) + .map(String::trim) + .filter(value -> !value.isEmpty()) + .map(Long::valueOf) + .collect(Collectors.toList()); + + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveIdsForDefaultActivity(ids, + ashaId, approvalStatus, + approvalDate, ashaSupervisorUserId, + ashaSupervisorDetails.getUserName()); } } From f20666f845e5bd04213b34347ecd2e9f31584448 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 15 Sep 2026 18:38:28 +0530 Subject: [PATCH 136/237] remove unwanted ssd portal code --- .../flw/domain/iemr/IncentiveActivity.java | 2 -- .../flw/dto/iemr/IncentiveActivityDTO.java | 1 - .../service/impl/IncentiveServiceImpl.java | 25 +++++-------------- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index 6402d9208..bba7fce3f 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -63,8 +63,6 @@ public class IncentiveActivity { @Column(name = "is_default_activity") private Boolean isDefaultActivity; - @Column(name = "group_category_name") - private String groupCategoryName; diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java index 7aa856463..0ebf4aac6 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java @@ -25,7 +25,6 @@ public class IncentiveActivityDTO implements Serializable { private String group; private String groupName; - private String groupCategoryName; private String fmrCode; diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index afe769e74..10cdcc117 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -152,12 +152,8 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { dto.setName(mapping.getName()); if (isCG) { - if (inc.getGroupCategoryName() != null - && !inc.getGroupCategoryName().isEmpty()) { - dto.setGroupName(inc.getGroupCategoryName()); - } else { - dto.setGroupName(inc.getGroup()); - } + dto.setGroupName(inc.getGroup()); + } else if (isAM) { dto.setGroupName(mapping.getGroup()); } @@ -180,12 +176,8 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { } else { if (isCG) { - if (inc.getGroupCategoryName() != null - && !inc.getGroupCategoryName().isEmpty()) { - dto.setGroupName(inc.getGroupCategoryName()); - } else { - dto.setGroupName(inc.getGroup()); - } + dto.setGroupName(inc.getGroup()); + } else { dto.setGroupName(inc.getGroup()); } @@ -500,13 +492,8 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege map.put("activityId", activityId); map.put("incentiveId",incentiveId); map.put("activityDec", activity.getDescription()); - if(activity.getGroupCategoryName()!=null && !activity.getGroupCategoryName().isEmpty()){ - map.put("groupName", activity.getGroupCategoryName()); - - }else { - map.put("groupName", activity.getGroup()); + map.put("groupName", activity.getGroup()); - } map.put("isDefault", activity.getIsDefaultActivity()); map.put("approvalStatus", approvalStatus); map.put("isApproved", isApproved); @@ -596,7 +583,7 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { incentivesRepo.findById(request.getActivityId()).orElse(null); String groupName = activity != null ? activity.getGroup() : ""; - String groupCategoryName = activity != null ? activity.getGroupCategoryName() :activity.getGroup(); + String groupCategoryName = activity != null ? activity.getGroup():""; String description = activity != null ? activity.getDescription() : ""; // 🔹 Map result From af7b5488b9c2e02646563638c4a41a950ac06fbe Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Sep 2026 12:11:38 +0530 Subject: [PATCH 137/237] fix is_approved nullable key issue --- .../flw/domain/iemr/IncentiveActivity.java | 2 ++ .../domain/iemr/IncentiveActivityRecord.java | 10 +++++++- .../flw/dto/iemr/IncentiveActivityDTO.java | 1 + .../service/impl/IncentiveServiceImpl.java | 25 ++++++++++++++----- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index bba7fce3f..6402d9208 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -63,6 +63,8 @@ public class IncentiveActivity { @Column(name = "is_default_activity") private Boolean isDefaultActivity; + @Column(name = "group_category_name") + private String groupCategoryName; diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java index d36f4865a..4a84055f0 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java @@ -91,5 +91,13 @@ public class IncentiveActivityRecord { @Transient String groupCategoryName; @Column(name = "is_approved") - private Boolean isApproved; + private Boolean isApproved = false; + + @PrePersist + @PreUpdate + private void applyDefaults() { + if (isApproved == null) { + isApproved = false; + } + } } diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java index 0ebf4aac6..7aa856463 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java @@ -25,6 +25,7 @@ public class IncentiveActivityDTO implements Serializable { private String group; private String groupName; + private String groupCategoryName; private String fmrCode; diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 10cdcc117..afe769e74 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -152,8 +152,12 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { dto.setName(mapping.getName()); if (isCG) { - dto.setGroupName(inc.getGroup()); - + if (inc.getGroupCategoryName() != null + && !inc.getGroupCategoryName().isEmpty()) { + dto.setGroupName(inc.getGroupCategoryName()); + } else { + dto.setGroupName(inc.getGroup()); + } } else if (isAM) { dto.setGroupName(mapping.getGroup()); } @@ -176,8 +180,12 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { } else { if (isCG) { - dto.setGroupName(inc.getGroup()); - + if (inc.getGroupCategoryName() != null + && !inc.getGroupCategoryName().isEmpty()) { + dto.setGroupName(inc.getGroupCategoryName()); + } else { + dto.setGroupName(inc.getGroup()); + } } else { dto.setGroupName(inc.getGroup()); } @@ -492,8 +500,13 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege map.put("activityId", activityId); map.put("incentiveId",incentiveId); map.put("activityDec", activity.getDescription()); - map.put("groupName", activity.getGroup()); + if(activity.getGroupCategoryName()!=null && !activity.getGroupCategoryName().isEmpty()){ + map.put("groupName", activity.getGroupCategoryName()); + }else { + map.put("groupName", activity.getGroup()); + + } map.put("isDefault", activity.getIsDefaultActivity()); map.put("approvalStatus", approvalStatus); map.put("isApproved", isApproved); @@ -583,7 +596,7 @@ public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { incentivesRepo.findById(request.getActivityId()).orElse(null); String groupName = activity != null ? activity.getGroup() : ""; - String groupCategoryName = activity != null ? activity.getGroup():""; + String groupCategoryName = activity != null ? activity.getGroupCategoryName() :activity.getGroup(); String description = activity != null ? activity.getDescription() : ""; // 🔹 Map result From f49a88d012da9034afd1cf48a74a961e3aa47d51 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Sep 2026 12:49:39 +0530 Subject: [PATCH 138/237] add new feature of update anc home visit --- .../domain/iemr/IncentiveActivityRecord.java | 10 ++- .../flw/dto/iemr/AncCounsellingCareDTO.java | 1 + .../impl/MaternalHealthServiceImpl.java | 71 +++++++++++++++---- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java index d36f4865a..4a84055f0 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java @@ -91,5 +91,13 @@ public class IncentiveActivityRecord { @Transient String groupCategoryName; @Column(name = "is_approved") - private Boolean isApproved; + private Boolean isApproved = false; + + @PrePersist + @PreUpdate + private void applyDefaults() { + if (isApproved == null) { + isApproved = false; + } + } } diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java index 76aff81da..b71086e0a 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java @@ -5,6 +5,7 @@ @Data public class AncCounsellingCareDTO { private String formId; + private Long id ; private Long beneficiaryId; private String visitDate; private AncCounsellingCareListDTO fields; diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 361211327..490d29484 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -447,15 +447,29 @@ public String savePNCVisit(List pncVisitDTOs) { @Override @Transactional - public String saveANCVisitQuestions(List dtos, String authorization) throws IEMRException { + public String saveANCVisitQuestions( + List dtos, + String authorization) throws IEMRException { + Integer userId = jwtUtil.extractUserId(authorization); String userName = userRepo.getUserNamedByUserId(userId); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + if (dtos == null || dtos.isEmpty()) { + throw new IllegalArgumentException("ANC visit data is mandatory"); + } + + DateTimeFormatter formatter = DateTimeFormatter + .ofPattern("dd-MM-uuuu") + .withResolverStyle(java.time.format.ResolverStyle.STRICT); + List entities = new ArrayList<>(); for (AncCounsellingCareDTO dto : dtos) { + if (dto == null) { + throw new IllegalArgumentException("ANC visit record cannot be null"); + } + if (!StringUtils.hasText(dto.getVisitDate())) { throw new IllegalArgumentException("visitDate is mandatory"); } @@ -469,21 +483,48 @@ public String saveANCVisitQuestions(List dtos, String aut try { visitDate = LocalDate.parse(dto.getVisitDate(), formatter); } catch (DateTimeParseException e) { - throw new IllegalArgumentException("Invalid visitDate format, expected dd-MM-yyyy"); + throw new IllegalArgumentException( + "Invalid visitDate, expected dd-MM-yyyy"); } LocalDate homeVisitDate; try { homeVisitDate = StringUtils.hasText(fields.getHomeVisitDate()) ? LocalDate.parse(fields.getHomeVisitDate(), formatter) - : visitDate; // ✅ fallback + : visitDate; } catch (DateTimeParseException e) { - throw new IllegalArgumentException("Invalid home_visit_date format, expected dd-MM-yyyy"); + throw new IllegalArgumentException( + "Invalid home_visit_date, expected dd-MM-yyyy"); + } + + AncCounsellingCare entity; + + if (dto.getId() != null) { + // Update existing record + entity = ancCounsellingCareRepo.findById(dto.getId()) + .orElseThrow(() -> new IllegalArgumentException( + "ANC visit not found for id: " + dto.getId())); + + // Only the record owner can update it + if (!java.util.Objects.equals(entity.getUserId(), userId)) { + throw new IllegalArgumentException( + "You are not authorized to update this ANC visit"); + } + + // Prevent moving an existing visit to another beneficiary + if (!java.util.Objects.equals( + entity.getBeneficiaryId(), dto.getBeneficiaryId())) { + throw new IllegalArgumentException( + "Beneficiary does not match the existing ANC visit"); + } + } else { + // Create new record + entity = new AncCounsellingCare(); + entity.setBeneficiaryId(dto.getBeneficiaryId()); + entity.setUserId(userId); + entity.setCreatedBy(userName); } - AncCounsellingCare entity = new AncCounsellingCare(); - entity.setBeneficiaryId(dto.getBeneficiaryId()); - entity.setAncVisitId(0L); entity.setVisitDate(visitDate); entity.setHomeVisitDate(homeVisitDate); @@ -492,28 +533,28 @@ public String saveANCVisitQuestions(List dtos, String aut entity.setHighBp(yesNoToBoolean(fields.getHighBp())); entity.setConvulsions(yesNoToBoolean(fields.getConvulsions())); entity.setAnemia(yesNoToBoolean(fields.getAnemia())); - entity.setReducedFetalMovement(yesNoToBoolean(fields.getReducedFetalMovement())); + entity.setReducedFetalMovement( + yesNoToBoolean(fields.getReducedFetalMovement())); entity.setAgeRisk(yesNoToBoolean(fields.getAgeRisk())); entity.setChildGap(yesNoToBoolean(fields.getChildGap())); entity.setShortHeight(yesNoToBoolean(fields.getShortHeight())); entity.setPrePregWeight(yesNoToBoolean(fields.getPrePregWeight())); entity.setBleeding(yesNoToBoolean(fields.getBleeding())); - entity.setMiscarriageHistory(yesNoToBoolean(fields.getMiscarriageHistory())); + entity.setMiscarriageHistory( + yesNoToBoolean(fields.getMiscarriageHistory())); entity.setFourPlusDelivery(yesNoToBoolean(fields.getFourPlusDelivery())); entity.setFirstDelivery(yesNoToBoolean(fields.getFirstDelivery())); entity.setTwinPregnancy(yesNoToBoolean(fields.getTwinPregnancy())); entity.setCSectionHistory(yesNoToBoolean(fields.getCSectionHistory())); - entity.setPreExistingDisease(yesNoToBoolean(fields.getPreExistingDisease())); + entity.setPreExistingDisease( + yesNoToBoolean(fields.getPreExistingDisease())); entity.setFeverMalaria(yesNoToBoolean(fields.getFeverMalaria())); entity.setJaundice(yesNoToBoolean(fields.getJaundice())); entity.setSickleCell(yesNoToBoolean(fields.getSickleCell())); entity.setProlongedLabor(yesNoToBoolean(fields.getProlongedLabor())); entity.setMalpresentation(yesNoToBoolean(fields.getMalpresentation())); - entity.setUserId(userId); - entity.setCreatedBy(userName); entity.setUpdatedBy(userName); - entities.add(entity); } @@ -569,7 +610,7 @@ public List getANCCounselling(GetBenRequestHandle fields.put("sickle_cell", booleanToYesNo(entity.getSickleCell())); fields.put("prolonged_labor", booleanToYesNo(entity.getProlongedLabor())); fields.put("malpresentation", booleanToYesNo(entity.getMalpresentation())); - + fields.put("id", entity.getId()); responseDTO.setFields(fields); responseDTOList.add(responseDTO); From 910604470f05ab95fc76e362403466898ccb85c6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Sep 2026 14:10:35 +0530 Subject: [PATCH 139/237] add new feature of update anc home visit --- .../com/iemr/flw/service/impl/MaternalHealthServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 490d29484..63fef105d 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -499,7 +499,7 @@ public String saveANCVisitQuestions( AncCounsellingCare entity; - if (dto.getId() != null) { + if (dto.getId() != null && dto.getId() > 0) { // Update existing record entity = ancCounsellingCareRepo.findById(dto.getId()) .orElseThrow(() -> new IllegalArgumentException( From 7038a3cd82bfad8fe3f834f796e8400316ed9391 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Sep 2026 14:30:28 +0530 Subject: [PATCH 140/237] add new feature of update anc home visit --- src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java index 46737f12a..16ada1717 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java @@ -25,7 +25,7 @@ public class AncCounsellingCare { private LocalDate homeVisitDate; @Column(name = "anc_visit_id", nullable = false) - private Long ancVisitId; + private Long ancVisitId=0L; @Column(name = "user_id") private Integer userId; @@ -124,5 +124,4 @@ protected void onUpdate() { } /* ---------- Getters & Setters ---------- */ - // Lombok use kar raha ho toh @Getter @Setter laga sakta hai } From 0ebd25be76db65e4ba8c52a397b9b81d9b80a940 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Sep 2026 14:57:08 +0530 Subject: [PATCH 141/237] add new feature of update anc home visit --- src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java | 3 +++ .../java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java | 3 +++ .../com/iemr/flw/service/impl/MaternalHealthServiceImpl.java | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java index 16ada1717..33e6b6fd5 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java @@ -107,6 +107,9 @@ public class AncCounsellingCare { @Column(name = "prolonged_labor") private Boolean prolongedLabor = false; + @Column(name = "visit_number") + private String visitNumber ; + @Column(name = "malpresentation") private Boolean malpresentation = false; diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java index 981e34e2b..87ebc4540 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java @@ -75,5 +75,8 @@ public class AncCounsellingCareListDTO { @SerializedName("malpresentation") private String malpresentation; + @SerializedName("visit_number") + private String visitNumber; + } diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 63fef105d..d57d6c999 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -553,6 +553,7 @@ public String saveANCVisitQuestions( entity.setSickleCell(yesNoToBoolean(fields.getSickleCell())); entity.setProlongedLabor(yesNoToBoolean(fields.getProlongedLabor())); entity.setMalpresentation(yesNoToBoolean(fields.getMalpresentation())); + entity.setVisitNumber(fields.getVisitNumber()); entity.setUpdatedBy(userName); entities.add(entity); @@ -611,6 +612,7 @@ public List getANCCounselling(GetBenRequestHandle fields.put("prolonged_labor", booleanToYesNo(entity.getProlongedLabor())); fields.put("malpresentation", booleanToYesNo(entity.getMalpresentation())); fields.put("id", entity.getId()); + fields.put("visit_number", entity.getVisitNumber()); responseDTO.setFields(fields); responseDTOList.add(responseDTO); From 286cda7aac6863cd4879fb44203917191c32ab3d Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Sep 2026 16:59:27 +0530 Subject: [PATCH 142/237] add new feature of update anc home visit --- src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java | 1 + .../com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java | 1 + .../com/iemr/flw/service/impl/MaternalHealthServiceImpl.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java index 33e6b6fd5..5ff703fdf 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java @@ -13,6 +13,7 @@ public class AncCounsellingCare { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") private Long id; @Column(name = "beneficiary_id", nullable = false) diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java index 2e0195582..8c8f0fb86 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java @@ -8,6 +8,7 @@ public class AncCounsellingCareResponseDTO { private String formId; private Long beneficiaryId; + private Long id; private String visitDate; private Map fields; // for dynamic form fields diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index d57d6c999..e60c45470 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -578,6 +578,7 @@ public List getANCCounselling(GetBenRequestHandle AncCounsellingCareResponseDTO responseDTO = new AncCounsellingCareResponseDTO(); responseDTO.setFormId("anc_form_001"); + responseDTO.setId(entity.getId()); responseDTO.setBeneficiaryId(entity.getBeneficiaryId()); // Update with actual value responseDTO.setVisitDate(entity.getVisitDate().format(formatter)); // Format visit.getVisitDate() From 038ce738b862ec94c58491c23dfab7e9b1f7c491 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Sep 2026 17:02:19 +0530 Subject: [PATCH 143/237] add new feature of update anc home visit --- .../java/com/iemr/flw/controller/MaternalHealthController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/flw/controller/MaternalHealthController.java b/src/main/java/com/iemr/flw/controller/MaternalHealthController.java index 9c8459daa..2e58d76ae 100644 --- a/src/main/java/com/iemr/flw/controller/MaternalHealthController.java +++ b/src/main/java/com/iemr/flw/controller/MaternalHealthController.java @@ -182,6 +182,7 @@ public ResponseEntity>> get logger.info("Request: " + requestDTO); List result = maternalHealthService.getANCCounselling(requestDTO); + logger.info("ANC Counselling result: {}", new Gson().toJson(result)); response.setStatusCode(200); response.setStatus("Success"); From 1f032439659ac594352c5f5da8a266cce456547e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Sep 2026 17:58:11 +0530 Subject: [PATCH 144/237] add new feature of update anc home visit --- .../impl/MaternalHealthServiceImpl.java | 47 ++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index e60c45470..9689325a4 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -505,18 +505,41 @@ public String saveANCVisitQuestions( .orElseThrow(() -> new IllegalArgumentException( "ANC visit not found for id: " + dto.getId())); - // Only the record owner can update it - if (!java.util.Objects.equals(entity.getUserId(), userId)) { - throw new IllegalArgumentException( - "You are not authorized to update this ANC visit"); - } - - // Prevent moving an existing visit to another beneficiary - if (!java.util.Objects.equals( - entity.getBeneficiaryId(), dto.getBeneficiaryId())) { - throw new IllegalArgumentException( - "Beneficiary does not match the existing ANC visit"); - } + entity.setBeneficiaryId(dto.getBeneficiaryId()); + entity.setUserId(userId); + entity.setCreatedBy(userName); + entity.setVisitDate(visitDate); + entity.setHomeVisitDate(homeVisitDate); + + entity.setSelectAll(yesNoToBoolean(fields.getSelectAll())); + entity.setSwelling(yesNoToBoolean(fields.getSwelling())); + entity.setHighBp(yesNoToBoolean(fields.getHighBp())); + entity.setConvulsions(yesNoToBoolean(fields.getConvulsions())); + entity.setAnemia(yesNoToBoolean(fields.getAnemia())); + entity.setReducedFetalMovement( + yesNoToBoolean(fields.getReducedFetalMovement())); + entity.setAgeRisk(yesNoToBoolean(fields.getAgeRisk())); + entity.setChildGap(yesNoToBoolean(fields.getChildGap())); + entity.setShortHeight(yesNoToBoolean(fields.getShortHeight())); + entity.setPrePregWeight(yesNoToBoolean(fields.getPrePregWeight())); + entity.setBleeding(yesNoToBoolean(fields.getBleeding())); + entity.setMiscarriageHistory( + yesNoToBoolean(fields.getMiscarriageHistory())); + entity.setFourPlusDelivery(yesNoToBoolean(fields.getFourPlusDelivery())); + entity.setFirstDelivery(yesNoToBoolean(fields.getFirstDelivery())); + entity.setTwinPregnancy(yesNoToBoolean(fields.getTwinPregnancy())); + entity.setCSectionHistory(yesNoToBoolean(fields.getCSectionHistory())); + entity.setPreExistingDisease( + yesNoToBoolean(fields.getPreExistingDisease())); + entity.setFeverMalaria(yesNoToBoolean(fields.getFeverMalaria())); + entity.setJaundice(yesNoToBoolean(fields.getJaundice())); + entity.setSickleCell(yesNoToBoolean(fields.getSickleCell())); + entity.setProlongedLabor(yesNoToBoolean(fields.getProlongedLabor())); + entity.setMalpresentation(yesNoToBoolean(fields.getMalpresentation())); + entity.setVisitNumber(fields.getVisitNumber()); + + entity.setUpdatedBy(userName); + entities.add(entity); } else { // Create new record entity = new AncCounsellingCare(); From b8e4d58b0ded00e6675cd56c086c9420f0ca5ccc Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 17 Sep 2026 14:28:07 +0530 Subject: [PATCH 145/237] add new feature of update anc home visit --- .../flw/domain/iemr/AncCounsellingCare.java | 2 - .../dto/iemr/AncCounsellingCareListDTO.java | 2 - .../impl/MaternalHealthServiceImpl.java | 38 ------------------- 3 files changed, 42 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java index 5ff703fdf..f8505f20d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java @@ -108,8 +108,6 @@ public class AncCounsellingCare { @Column(name = "prolonged_labor") private Boolean prolongedLabor = false; - @Column(name = "visit_number") - private String visitNumber ; @Column(name = "malpresentation") private Boolean malpresentation = false; diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java index 87ebc4540..984425149 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java @@ -75,8 +75,6 @@ public class AncCounsellingCareListDTO { @SerializedName("malpresentation") private String malpresentation; - @SerializedName("visit_number") - private String visitNumber; } diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 9689325a4..81eeb4ec8 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -504,42 +504,6 @@ public String saveANCVisitQuestions( entity = ancCounsellingCareRepo.findById(dto.getId()) .orElseThrow(() -> new IllegalArgumentException( "ANC visit not found for id: " + dto.getId())); - - entity.setBeneficiaryId(dto.getBeneficiaryId()); - entity.setUserId(userId); - entity.setCreatedBy(userName); - entity.setVisitDate(visitDate); - entity.setHomeVisitDate(homeVisitDate); - - entity.setSelectAll(yesNoToBoolean(fields.getSelectAll())); - entity.setSwelling(yesNoToBoolean(fields.getSwelling())); - entity.setHighBp(yesNoToBoolean(fields.getHighBp())); - entity.setConvulsions(yesNoToBoolean(fields.getConvulsions())); - entity.setAnemia(yesNoToBoolean(fields.getAnemia())); - entity.setReducedFetalMovement( - yesNoToBoolean(fields.getReducedFetalMovement())); - entity.setAgeRisk(yesNoToBoolean(fields.getAgeRisk())); - entity.setChildGap(yesNoToBoolean(fields.getChildGap())); - entity.setShortHeight(yesNoToBoolean(fields.getShortHeight())); - entity.setPrePregWeight(yesNoToBoolean(fields.getPrePregWeight())); - entity.setBleeding(yesNoToBoolean(fields.getBleeding())); - entity.setMiscarriageHistory( - yesNoToBoolean(fields.getMiscarriageHistory())); - entity.setFourPlusDelivery(yesNoToBoolean(fields.getFourPlusDelivery())); - entity.setFirstDelivery(yesNoToBoolean(fields.getFirstDelivery())); - entity.setTwinPregnancy(yesNoToBoolean(fields.getTwinPregnancy())); - entity.setCSectionHistory(yesNoToBoolean(fields.getCSectionHistory())); - entity.setPreExistingDisease( - yesNoToBoolean(fields.getPreExistingDisease())); - entity.setFeverMalaria(yesNoToBoolean(fields.getFeverMalaria())); - entity.setJaundice(yesNoToBoolean(fields.getJaundice())); - entity.setSickleCell(yesNoToBoolean(fields.getSickleCell())); - entity.setProlongedLabor(yesNoToBoolean(fields.getProlongedLabor())); - entity.setMalpresentation(yesNoToBoolean(fields.getMalpresentation())); - entity.setVisitNumber(fields.getVisitNumber()); - - entity.setUpdatedBy(userName); - entities.add(entity); } else { // Create new record entity = new AncCounsellingCare(); @@ -576,7 +540,6 @@ public String saveANCVisitQuestions( entity.setSickleCell(yesNoToBoolean(fields.getSickleCell())); entity.setProlongedLabor(yesNoToBoolean(fields.getProlongedLabor())); entity.setMalpresentation(yesNoToBoolean(fields.getMalpresentation())); - entity.setVisitNumber(fields.getVisitNumber()); entity.setUpdatedBy(userName); entities.add(entity); @@ -636,7 +599,6 @@ public List getANCCounselling(GetBenRequestHandle fields.put("prolonged_labor", booleanToYesNo(entity.getProlongedLabor())); fields.put("malpresentation", booleanToYesNo(entity.getMalpresentation())); fields.put("id", entity.getId()); - fields.put("visit_number", entity.getVisitNumber()); responseDTO.setFields(fields); responseDTOList.add(responseDTO); From 6a5c037f18ea16470845262eb6520d0c64a962ed Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 18 Sep 2026 15:05:24 +0530 Subject: [PATCH 146/237] fix incentive approval for anm --- .../flw/repo/iemr/IncentiveRecordRepo.java | 24 +++++++++++++++++++ .../impl/SupervisorDashboardServiceImpl.java | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 1663917d8..bc6587dea 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -398,6 +398,30 @@ int updateApprovalStatusByIncentiveIdsForDefaultActivity( @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, @Param("ashaSupervisorUserName") String ashaSupervisorUserName ); + + + @Modifying + @Transactional + @Query(""" + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.approvalDate = :approvalDate, + iar.reason = NULL, + iar.otherReason = NULL + WHERE iar.id IN :incentiveIds + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + """) + int updateApprovalStatusByIncentiveIdsForDefaultActivityForAnm( + @Param("incentiveIds") List incentiveIds, + @Param("ashaId") Integer ashaId, + @Param("approvalStatus") Integer approvalStatus, + @Param("approvalDate") Timestamp approvalDate, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName + ); @Modifying @Transactional @Query("UPDATE IncentiveActivityRecord iar " diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index f4cc1c07c..cf4fe84e6 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1696,7 +1696,7 @@ public int updateApprovalStatus(Integer ashaId, .map(Long::valueOf) .collect(Collectors.toList()); - updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveIdsForDefaultActivity(ids, + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveIdsForDefaultActivityForAnm(ids, ashaId, approvalStatus, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); From d5817965ffe88480e45479c41bf461dc71372f54 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 18 Sep 2026 15:08:34 +0530 Subject: [PATCH 147/237] fix incentive approval for anm --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index cf4fe84e6..cc287117d 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1696,7 +1696,7 @@ public int updateApprovalStatus(Integer ashaId, .map(Long::valueOf) .collect(Collectors.toList()); - updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveIdsForDefaultActivityForAnm(ids, + updatedCount = incentiveRecordRepo.updateApprovalStatusByIncentiveIds(ids, ashaId, approvalStatus, approvalDate, ashaSupervisorUserId, ashaSupervisorDetails.getUserName()); From 10ff79522f622e9a01ad1a3c7554590d7b4e4738 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 18 Sep 2026 16:07:32 +0530 Subject: [PATCH 148/237] merge 3.10.0 to main --- src/main/environment/common_ci.properties | 29 +++++++++ src/main/environment/common_docker.properties | 41 +++++++++++++ .../identity/RMNCHHouseHoldDetails.java | 24 ++++++++ .../identity/RMNCHMBeneficiarydetail.java | 32 ++++++++++ .../flw/domain/iemr/IncentiveActivity.java | 4 -- .../dto/identity/GetBenRequestHandler.java | 14 +++++ .../flw/repo/identity/BeneficiaryRepo.java | 5 ++ .../iemr/flw/service/ChildCareService.java | 1 + .../impl/AbhaBeneficiaryServiceImpl.java | 6 +- .../service/impl/ChildCareServiceImpl.java | 41 +++++++++++++ .../impl/MalariaFollowUpServiceImpl.java | 3 + .../flw/service/impl/UTPReronaPaymentJob.java | 6 +- .../impl/UtpreronaPaymentIntegrationImpl.java | 4 +- src/main/resources/application.properties | 60 +++++++++++++++++++ 14 files changed, 260 insertions(+), 10 deletions(-) diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 50ae20303..f2f3e0202 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -50,4 +50,33 @@ govthealth.user.details.url=@env.GOVTHEALTH_USER_DETAILS_URL@ govthealth.user.id=@env.GOVTHEALTH_USER_ID@ govthealth.password=@env.GOVTHEALTH_PASSWORD@ +# ── Diagnostic Device Integration ──────────────────────────────────────────── +# diagnostic.provider.xray / diagnostic.provider.truenat select the vendor per orderType family +# (XRAY_CHEST vs MTB/MTB_PLUS/MDR_RIF), each must be one of com.iemr.flw.masterEnum.DiagnosticProviderCode +diagnostic.provider.xray=@env.DIAGNOSTIC_PROVIDER_XRAY@ +diagnostic.provider.truenat=@env.DIAGNOSTIC_PROVIDER_TRUENAT@ + +# EMR Lite - xray group (same base-url as truenat for now; split so a distinct vendor/tenant can be +# swapped in for either group later without a code change) +diagnostic.emrlite.xray.base-url=@env.DIAGNOSTIC_EMRLITE_XRAY_BASE_URL@ +diagnostic.emrlite.xray.login-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/login/ +diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/getAccessToken/ +diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/ +diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/ +diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.xray.username=@env.DIAGNOSTIC_EMRLITE_XRAY_USERNAME@ +diagnostic.emrlite.xray.password=@env.DIAGNOSTIC_EMRLITE_XRAY_PASSWORD@ + +# EMR Lite - truenat group (MTB/MTB_PLUS/MDR_RIF); same value as xray for now +diagnostic.emrlite.truenat.base-url=@env.DIAGNOSTIC_EMRLITE_TRUENAT_BASE_URL@ +diagnostic.emrlite.truenat.login-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/login/ +diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/getAccessToken/ +diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/ +diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/ +diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.truenat.username=@env.DIAGNOSTIC_EMRLITE_TRUENAT_USERNAME@ +diagnostic.emrlite.truenat.password=@env.DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD@ + +diagnostic.emrlite.token-ttl-seconds=@env.DIAGNOSTIC_EMRLITE_TOKEN_TTL_SECONDS@ +diagnostic.emrlite.refresh-ttl-seconds=@env.DIAGNOSTIC_EMRLITE_REFRESH_TTL_SECONDS@ diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index 8a31d5d6f..6c1f908c6 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -30,6 +30,11 @@ jwt.secret=${JWT_SECRET_KEY} # Redis Config spring.redis.host=${REDIS_HOST} +# Stop TB: when true, saves fail with an error if camp (vanID) is not configured +stoptb.enforce.vanid=${STOPTB_ENFORCE_VANID} +# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup +stoptb.van.id=${STOPTB_VAN_ID} + #### SMS Configuration send-sms=${SEND_SMS} source-address=${SMS_CONSENT_SOURCE_ADDRESS} @@ -51,5 +56,41 @@ govthealth.user.details.url=${GOVTHEALTH_USER_DETAILS_URL} govthealth.user.id=${GOVTHEALTH_USER_ID} govthealth.password=${GOVTHEALTH_PASSWORD} +# ── Diagnostic Device Integration ──────────────────────────────────────────── +# diagnostic.provider.xray / diagnostic.provider.truenat select the vendor per orderType family +# (XRAY_CHEST vs MTB/MTB_PLUS/MDR_RIF), each must be one of com.iemr.flw.masterEnum.DiagnosticProviderCode +diagnostic.provider.xray=${DIAGNOSTIC_PROVIDER_XRAY} +diagnostic.provider.truenat=${DIAGNOSTIC_PROVIDER_TRUENAT} + +# EMR Lite - xray group (same base-url as truenat for now; split so a distinct vendor/tenant can be +# swapped in for either group later without a code change) +diagnostic.emrlite.xray.base-url=${DIAGNOSTIC_EMRLITE_XRAY_BASE_URL} +diagnostic.emrlite.xray.login-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/login/ +diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/getAccessToken/ +diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/ +diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/ +diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.xray.username=${DIAGNOSTIC_EMRLITE_XRAY_USERNAME} +diagnostic.emrlite.xray.password=${DIAGNOSTIC_EMRLITE_XRAY_PASSWORD} + +# EMR Lite - truenat group (MTB/MTB_PLUS/MDR_RIF); same value as xray for now +diagnostic.emrlite.truenat.base-url=${DIAGNOSTIC_EMRLITE_TRUENAT_BASE_URL} +diagnostic.emrlite.truenat.login-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/login/ +diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/getAccessToken/ +diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/ +diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/ +diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.truenat.username=${DIAGNOSTIC_EMRLITE_TRUENAT_USERNAME} +diagnostic.emrlite.truenat.password=${DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD} + +diagnostic.emrlite.token-ttl-seconds=${DIAGNOSTIC_EMRLITE_TOKEN_TTL_SECONDS} +diagnostic.emrlite.refresh-ttl-seconds=${DIAGNOSTIC_EMRLITE_REFRESH_TTL_SECONDS} + +diagnostic.poll.xray.tick-ms=${DIAGNOSTIC_POLL_XRAY_TICK_MS} +diagnostic.poll.truenat.tick-ms=${DIAGNOSTIC_POLL_TRUENAT_TICK_MS} +# Daily cutoff (cron expression) after which all outstanding PENDING/IN_PROGRESS orders are marked EXPIRED +diagnostic.poll.expiry-cron=${DIAGNOSTIC_POLL_EXPIRY_CRON} + +diagnostic.documents.storage-root=${DIAGNOSTIC_DOCUMENTS_STORAGE_ROOT} 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 3a3ccec86..20cd8bfbf 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,28 @@ public class RMNCHHouseHoldDetails { @Column(name = "isDeactivate") private Boolean isDeactivate; + @Expose + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Expose + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Expose + @Column(name = "address") + private String address; + + @Expose + @Column(name = "totalHhMembers") + private Integer totalHhMembers; + + @Expose + @Column(name = "registeredAtCampSite") + private String registeredAtCampSite; + + @Expose + @Column(name = "registeredAtCampSiteId") + private Integer registeredAtCampSiteId; + } diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java index 779a09da4..89a1a80db 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java @@ -190,4 +190,36 @@ public class RMNCHMBeneficiarydetail { @Column(name = "familyid") private String familyId; + @Column(name = "ExtraFields") + private String otherFields; + + @Expose + @Column(name = "economicStatus") + private String economicStatus; + + @Expose + @Column(name = "economicStatusId") + private Integer economicStatusId; + + @Expose + @Column(name = "residentialArea") + private String residentialArea; + + @Expose + @Column(name = "residentialAreaId") + private Integer residentialAreaId; + + @Expose + @Column(name = "address") + private String address; + + @Expose + private String placeOfCurrentLiving; + + @Expose + private String otherPlaceOfCurrentLiving; + + @Expose + private String institutionName; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index a2f238b8c..6402d9208 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -68,8 +68,4 @@ public class IncentiveActivity { - @Column(name = "state_activity_code") - private Integer stateActivityCode; - - } diff --git a/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java b/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java index 37dc9761f..957d8a86d 100644 --- a/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java +++ b/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java @@ -13,6 +13,16 @@ public class GetBenRequestHandler { private Integer ashaId; + private Integer providerServiceMapID; + + public Integer getProviderServiceMapID() { + return providerServiceMapID; + } + + public void setProviderServiceMapID(Integer providerServiceMapID) { + this.providerServiceMapID = providerServiceMapID; + } + private Long activityId; private Integer month; @@ -83,6 +93,10 @@ public void setVillageID(Integer villageID) { this.villageID = villageID; } + public void setVillageId(Integer villageId) { + this.villageID = villageId; + } + public Timestamp getFromDate() { return fromDate; } diff --git a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java index a6ee9700c..d37789d11 100644 --- a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java +++ b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java @@ -161,4 +161,9 @@ SELECT COUNT(*) @Query("SELECT t FROM RMNCHMBeneficiaryaddress t WHERE t.benAddressID IN :ids") List findAddressesByIds(@Param("ids") List ids); + + @Query("SELECT b.BenRegId, b.benficieryid " + + "FROM RMNCHBeneficiaryDetailsRmnch b " + + "WHERE b.BenRegId IN :regIds AND b.benficieryid IS NOT NULL") + List getBenIdsFromRegIds(@Param("regIds") List regIds); } diff --git a/src/main/java/com/iemr/flw/service/ChildCareService.java b/src/main/java/com/iemr/flw/service/ChildCareService.java index c78de3fdc..a7e526e69 100644 --- a/src/main/java/com/iemr/flw/service/ChildCareService.java +++ b/src/main/java/com/iemr/flw/service/ChildCareService.java @@ -16,6 +16,7 @@ public interface ChildCareService { List getHBNCDetails(GetBenRequestHandler dto); String saveHBNCDetails(List hbncRequestDTOs,Integer userId); + String saveHBNCDetails(List hbncRequestDTOs); List getChildVaccinationDetails(GetBenRequestHandler dto); diff --git a/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java index 15ca0e7cc..f9098c398 100644 --- a/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.iemr.flw.controller.AbhaBeneficiaryController; import com.iemr.flw.domain.iemr.AbhaApiResponse; +import com.iemr.flw.domain.identity.RMNCHMBeneficiarymapping; import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; import com.iemr.flw.dto.iemr.AbhaRequestDTO; import com.iemr.flw.repo.identity.BeneficiaryRepo; @@ -55,7 +56,10 @@ public Object getBeneficiaryByAbha(AbhaRequestDTO request) { if(request.getHouseHoldId()!=null){ benRedId = beneficiaryRepo.findByHouseoldId(request.getHouseHoldId()).get(0).getBenRegId(); if(benRedId!=null){ - benDetailsdId = beneficiaryRepo.findByBenRegIdFromMapping(BigInteger.valueOf(benRedId)).getBenDetailsId(); + List mappings = beneficiaryRepo.findByBenRegIdFromMapping(BigInteger.valueOf(benRedId)); + if (!mappings.isEmpty()) { + benDetailsdId = mappings.get(0).getBenDetailsId(); + } } if(benDetailsdId!=null){ diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 6660b9b06..60cfa29f2 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -372,6 +372,47 @@ public String saveHBNCDetails(List hbncRequestDTOs, Integer user return null; } + @Override + public String saveHBNCDetails(List hbncRequestDTOs) { + try { + List hbncList = new ArrayList<>(); + + hbncRequestDTOs.forEach(it -> { + if (it.getVisitDate() != null) { + + HbncVisitDTO hbncVisitDTO = it.getFields(); + hbncVisitDTO.setVisit_date(it.getVisitDate()); + HbncVisit hbncVisit = hbncVisitRepo.findByBeneficiaryIdAndVisit_day(it.getBeneficiaryId(), hbncVisitDTO.getVisit_day()); + + if (hbncVisit != null) { + Long id = hbncVisit.getId(); + modelMapper.map(hbncVisitDTO, hbncVisit); + hbncVisit.setId(id); + } else { + hbncVisit = new HbncVisit(); + modelMapper.map(hbncVisitDTO, hbncVisit); + hbncVisit.setBeneficiaryId(it.getBeneficiaryId()); + hbncVisit.setAshaId(userRepo.getUserIdByName(it.getUserName())); + hbncVisit.setCreatedBy(it.getUserName()); + hbncVisit.setHouseHoldId(it.getHouseHoldId()); + hbncVisit.setId(null); + } + hbncList.add(hbncVisit); + } + }); + + + hbncVisitRepo.saveAll(hbncList); + + + logger.info("HBNC details saved"); + return "no of hbnc details saved: " + (hbncList.size()); + } catch (Exception e) { + logger.info("Saving HBNC details failed with error : " + e.getMessage()); + } + return null; + } + @Override public List getChildVaccinationDetails(GetBenRequestHandler dto) { try { diff --git a/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java index f5ef4a092..ac4f74373 100644 --- a/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java @@ -51,6 +51,7 @@ public Boolean saveFollowUp(MalariaFollowUpDTO malariaFollowUpDTO,String token) dto.setUserId(jwtUtil.extractUserId(token)); MalariaFollowUp entity = new MalariaFollowUp(); BeanUtils.copyProperties(dto, entity); + entity.setModifiedBy(jwtUtil.extractUsername(token)); repository.save(entity); if(entity!=null){ incentiveLogicService.incentiveForMalariaFollowUp( @@ -76,6 +77,8 @@ public List getByUserId(Integer userId) { return repository.findByUserId(userId).stream().map(entity -> { MalariaFollowListUpDTO dto = new MalariaFollowListUpDTO(); BeanUtils.copyProperties(entity, dto); + dto.setUpdateDate(entity.getLastModDate()); + dto.setUpdatedBy(entity.getModifiedBy()); return dto; }).collect(Collectors.toList()); } diff --git a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java index 7a8e751ba..30a791020 100644 --- a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java +++ b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java @@ -49,13 +49,13 @@ public void run(String... args) { log.info("FLW application started successfully and is now running."); log.info("========================================"); + triggerStaticPayment(); } // ✅ Separate method — call this for immediate testing public void triggerStaticPayment() { try { - Period period = new Period(); period.setStart("2026-01-01"); period.setEnd("2026-01-31"); @@ -79,10 +79,10 @@ public void triggerStaticPayment() { items.add(item2); PaymentRequest paymentRequest = new PaymentRequest( - "4d0d8f3a-0bh9b-fff4e7edd-8bdd7a-rfgggdjhdd", + "4d0d8f3a-0bh9b-fff4e7edd-8bdd7a-rfgggdjhCCrrj", "AMRIT", period, - "4566", + "1857708", "2026-02-01T02:00:00+05:30", verifiedBy, items diff --git a/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java b/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java index e277cc318..ad4e7d381 100644 --- a/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java @@ -16,10 +16,10 @@ public class UtpreronaPaymentIntegrationImpl { private String API_URL = - "https://nhmssd.assam.gov.in/APPMS_2024_25/api/utpreronaPayment.php"; + "https://nhmssd.assam.gov.in/APPMS_2024_25/api/api_receipt_entry.php"; private String API_KEY = - "YOUR_API_KEY"; + "41202fa384eab2725a17bbac58cf708bf04cd1dd5175010941606156dc36d6b5"; private static final int TIMEOUT_SECONDS = 30; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0b93c5177..2ffd6d6b8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -72,3 +72,63 @@ spring.redis.password= spring.redis.port=6379 notificationurl=firebaseNotification/sendNotification + + + +server.port=8081 +# FHIR Config + +# TM Config +##--------------------------------------------## Primary db------------------------------------------------------------------- + +spring.datasource.url=jdbc:mysql://localhost:3306/db_iemr +spring.datasource.username=root +spring.datasource.password=1234 +spring.datasource.driver-class-name=com.mysql.jdbc.Driver + +##--------------------------------------------## Secondary db------------------------------------------------------------------- + +secondary.datasource.url=jdbc:mysql://localhost:3306/db_identity +secondary.datasource.username=root +secondary.datasource.password=1234 +secondary.datasource.driver-class-name=com.mysql.jdbc.Driver + + + +logging.path=logs/ +logging.file.name=logs/flw-api.log + +jwt.secret=my-32-character-ultra-secure-and-ultra-long-secret + +# Redis Config + +cors.allowed-origins=http://localhost:* + +source-address= +sms-username= +sms-password= +send-message-url= + +crash.logs.base.path= + +# ABHA Token Config +abha.client.id= +abha.client.secret= +abha.token.url= +abha.xcmid= + + +#crash.logs.base.path=@env.CRASH_LOGS_PATH@ + +# ABHA Token Config + + +# GovThealth API Config +govthealth.user.details.url=@env.GOVTHEALTH_USER_DETAILS_URL@ +govthealth.user.id=@env.GOVTHEALTH_USER_ID@ +govthealth.password=@env.GOVTHEALTH_PASSWORD@ +common-api-base-url= + + + + From 60d6b16a8eead19232fc6f25cf26186b1a7a12dc Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 21 Sep 2026 15:53:30 +0530 Subject: [PATCH 149/237] fix hbnc visit isssue --- .../identity/RMNCHHouseHoldDetails.java | 413 +++++++++--------- .../com/iemr/flw/dto/iemr/HbncVisitDTO.java | 4 +- 2 files changed, 209 insertions(+), 208 deletions(-) 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 3a3ccec86..87539a8b1 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java @@ -4,6 +4,7 @@ import lombok.Data; import jakarta.persistence.*; + import java.sql.Timestamp; @Entity @@ -11,282 +12,282 @@ @Data public class RMNCHHouseHoldDetails { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Expose - @Column(name = "houseHoldDetailsId", insertable = false, updatable = false) - private Long houseHoldDetailsId; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Expose + @Column(name = "houseHoldDetailsId", insertable = false, updatable = false) + private Long houseHoldDetailsId; - @Expose - @Column(name = "BeneficiaryRegID") - private Long BenRegId; + @Expose + @Column(name = "BeneficiaryRegID") + private Long BenRegId; - @Expose - @Column(name = "Countyid") - private Integer Countyid; + @Expose + @Column(name = "Countyid") + private Integer Countyid; - @Expose - @Column(name = "availabilityofToilet") - private String availabilityofToilet; + @Expose + @Column(name = "availabilityofToilet") + private String availabilityofToilet; - @Expose - @Column(name = "availabilityofToiletId") - private Integer availabilityofToiletId; + @Expose + @Column(name = "availabilityofToiletId") + private Integer availabilityofToiletId; - @Expose - @Column(name = "avalabilityofElectricity") - private String avalabilityofElectricity; + @Expose + @Column(name = "avalabilityofElectricity") + private String avalabilityofElectricity; - @Expose - @Column(name = "avalabilityofElectricityId") - private Integer avalabilityofElectricityId; + @Expose + @Column(name = "avalabilityofElectricityId") + private Integer avalabilityofElectricityId; - @Expose - @Column(name = "block") - private String block; + @Expose + @Column(name = "block") + private String block; - @Expose - @Column(name = "bpl_aplId") - private Integer bpl_aplId; + @Expose + @Column(name = "bpl_aplId") + private Integer bpl_aplId; - @Expose - @Column(name = "colony") - private String colony; + @Expose + @Column(name = "colony") + private String colony; - @Expose - @Column(name = "district") - private String district; + @Expose + @Column(name = "district") + private String district; - @Expose - @Column(name = "districtid") - private Integer districtid; + @Expose + @Column(name = "districtid") + private Integer districtid; - @Expose - @Column(name = "districtname") - private String districtname; + @Expose + @Column(name = "districtname") + private String districtname; - @Expose - @Column(name = "familyHeadName") - private String familyHeadName; + @Expose + @Column(name = "familyHeadName") + private String familyHeadName; - @Expose - @Column(name = "familyHeadPhoneNo") - private String familyHeadPhoneNo; + @Expose + @Column(name = "familyHeadPhoneNo") + private String familyHeadPhoneNo; - @Expose - @Column(name = "familyName") - private String familyName; + @Expose + @Column(name = "familyName") + private String familyName; - @Expose - @Column(name = "fuelUsed") - private String fuelUsed; + @Expose + @Column(name = "fuelUsed") + private String fuelUsed; - @Expose - @Column(name = "fuelUsedId") - private Integer fuelUsedId; + @Expose + @Column(name = "fuelUsedId") + private Integer fuelUsedId; - @Expose - @Column(name = "houseOwnerShip") - private String houseOwnerShip; + @Expose + @Column(name = "houseOwnerShip") + private String houseOwnerShip; - @Expose - @Column(name = "houseOwnerShipId") - private Integer houseOwnerShipId; + @Expose + @Column(name = "houseOwnerShipId") + private Integer houseOwnerShipId; - @Expose - @Column(name = "houseType") - private String houseType; + @Expose + @Column(name = "houseType") + private String houseType; - @Expose - @Column(name = "houseTypeId") - private Integer houseTypeId; + @Expose + @Column(name = "houseTypeId") + private Integer houseTypeId; - @Expose - @Column(name = "houseno") - private String houseno; + @Expose + @Column(name = "houseno") + private String houseno; - @Expose - @Column(name = "houseNum") - private String houseNum; - @Expose - @Column(name = "houseoldId") - private Long houseoldId; + @Expose + @Column(name = "houseNum") + private String houseNum; + @Expose + @Column(name = "houseoldId") + private Long houseoldId; - @Expose - @Column(name = "landIrregatedId") - private Integer landIrregatedId; + @Expose + @Column(name = "landIrregatedId") + private Integer landIrregatedId; - @Expose - @Column(name = "landOwnedId") - private Integer landOwnedId; + @Expose + @Column(name = "landOwnedId") + private Integer landOwnedId; - @Expose - @Column(name = "liveStockOwnerShipId") - private Integer liveStockOwnerShipId; + @Expose + @Column(name = "liveStockOwnerShipId") + private Integer liveStockOwnerShipId; - @Expose - @Column(name = "motarizedVehicleId") - private Integer motarizedVehicleId; + @Expose + @Column(name = "motarizedVehicleId") + private Integer motarizedVehicleId; - @Expose - @Column(name = "other_availabilityofToilet") - private String other_availabilityofToilet; + @Expose + @Column(name = "other_availabilityofToilet") + private String other_availabilityofToilet; - @Expose - @Column(name = "other_avalabilityofElectricity") - private String other_avalabilityofElectricity; + @Expose + @Column(name = "other_avalabilityofElectricity") + private String other_avalabilityofElectricity; - @Expose - @Column(name = "other_fuelUsed") - private String other_fuelUsed; + @Expose + @Column(name = "other_fuelUsed") + private String other_fuelUsed; - @Expose - @Column(name = "other_houseType") - private String other_houseType; + @Expose + @Column(name = "other_houseType") + private String other_houseType; - @Expose - @Column(name = "other_motarizedVehicle") - private String other_motarizedVehicle; + @Expose + @Column(name = "other_motarizedVehicle") + private String other_motarizedVehicle; - @Expose - @Column(name = "other_residentialArea") - private String other_residentialArea; + @Expose + @Column(name = "other_residentialArea") + private String other_residentialArea; - @Expose - @Column(name = "other_sourceofDrinkingWater") - private String other_sourceofDrinkingWater; + @Expose + @Column(name = "other_sourceofDrinkingWater") + private String other_sourceofDrinkingWater; - @Expose - @Column(name = "pincode") - private Integer pincode; + @Expose + @Column(name = "pincode") + private Integer pincode; - @Expose - @Column(name = "rationCardDetails") - private String rationCardDetails; + @Expose + @Column(name = "rationCardDetails") + private String rationCardDetails; - @Expose - @Column(name = "residentialArea") - private String residentialArea; + @Expose + @Column(name = "residentialArea") + private String residentialArea; @Expose @Column(name = "residentialAreaId") private Integer residentialAreaId; - @Expose - @Column(name = "seperateKitchen") - private String seperateKitchen; + @Expose + @Column(name = "seperateKitchen") + private String seperateKitchen; - @Expose - @Column(name = "seperateKitchenId") - private Integer seperateKitchenId; + @Expose + @Column(name = "seperateKitchenId") + private Integer seperateKitchenId; - @Expose - @Column(name = "serverUpdatedStatus") - private Integer serverUpdatedStatus; + @Expose + @Column(name = "serverUpdatedStatus") + private Integer serverUpdatedStatus; - @Expose - @Column(name = "sourceofDrinkingWater") - private String sourceofDrinkingWater; + @Expose + @Column(name = "sourceofDrinkingWater") + private String sourceofDrinkingWater; - @Expose - @Column(name = "sourceofDrinkingWaterId") - private Integer sourceofDrinkingWaterId; + @Expose + @Column(name = "sourceofDrinkingWaterId") + private Integer sourceofDrinkingWaterId; - @Expose - @Column(name = "state") - private String state; + @Expose + @Column(name = "state") + private String state; - @Expose - @Column(name = "stateid") - private Integer stateid; + @Expose + @Column(name = "stateid") + private Integer stateid; - @Expose - @Column(name = "street") - private String street; + @Expose + @Column(name = "street") + private String street; - @Expose - @Column(name = "type_bpl_apl") - private String type_bpl_apl; + @Expose + @Column(name = "type_bpl_apl") + private String type_bpl_apl; - @Expose - @Column(name = "village") - private String village; + @Expose + @Column(name = "village") + private String village; - @Expose - @Column(name = "villageid") - private Integer villageid; + @Expose + @Column(name = "villageid") + private Integer villageid; - @Expose - @Column(name = "Deleted") - private Boolean deleted; + @Expose + @Column(name = "Deleted") + private Boolean deleted; - @Expose - @Column(name = "Processed") - private String Processed = "N"; + @Expose + @Column(name = "Processed") + private String Processed = "N"; - @Expose - @Column(name = "CreatedBy") - private String createdBy; + @Expose + @Column(name = "CreatedBy") + private String createdBy; - @Expose - @Column(name = "CreatedDate") - private Timestamp createdDate; + @Expose + @Column(name = "CreatedDate") + private Timestamp createdDate; - @Expose - @Column(name = "Reserved") - private Boolean reserved; + @Expose + @Column(name = "Reserved") + private Boolean reserved; - @Expose - @Column(name = "ReservedFor") - private String reservedFor; + @Expose + @Column(name = "ReservedFor") + private String reservedFor; - @Expose - @Column(name = "ReservedOn") - private String reservedOn; + @Expose + @Column(name = "ReservedOn") + private String reservedOn; - @Expose - @Column(name = "ReservedById") - private Integer reservedById; + @Expose + @Column(name = "ReservedById") + private Integer reservedById; - @Expose - @Column(name = "ModifiedBy") - private String modifiedBy; + @Expose + @Column(name = "ModifiedBy") + private String modifiedBy; - @Expose - @Column(name = "LastModDate") - private Timestamp lastModDate; + @Expose + @Column(name = "LastModDate") + private Timestamp lastModDate; - @Expose - @Column(name = "VanSerialNo") - private Long id; + @Expose + @Column(name = "VanSerialNo") + private Long id; - @Expose - @Column(name = "VanID") - private Integer VanID; + @Expose + @Column(name = "VanID") + private Integer VanID; - @Expose - @Column(name = "VehicalNo") - private String vehicalNo; + @Expose + @Column(name = "VehicalNo") + private String vehicalNo; - @Expose - @Column(name = "ParkingPlaceID") - private Integer parkingPlaceID; + @Expose + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceID; - @Expose - @Column(name = "SyncedBy") - private String syncedBy; + @Expose + @Column(name = "SyncedBy") + private String syncedBy; - @Expose - @Column(name = "SyncedDate") - private Timestamp syncedDate; + @Expose + @Column(name = "SyncedDate") + private Timestamp syncedDate; - @Expose - @Column(name = "ProviderServiceMapID") - private Integer ProviderServiceMapID; + @Expose + @Column(name = "ProviderServiceMapID") + private Integer ProviderServiceMapID; - @Expose - @Column(name = "deviceId") - private Integer deviceId; + @Expose + @Column(name = "deviceId") + private Integer deviceId; @Expose @Column(name = "beneficiaryId") diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java index d5cc8acf0..a5043b22c 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java @@ -93,8 +93,8 @@ public class HbncVisitDTO { @Column(name = "baby_eyes_swollen") private Boolean babyEyesSwollen; - @Column(name = "is_admitted_in_sncu") - private Boolean is_admitted_in_sncu; + @SerializedName("is_admitted_in_sncu") + private String is_admitted_in_sncu; } From 316ac0ecf3e960daf89477650266254069462278 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 21 Sep 2026 16:02:48 +0530 Subject: [PATCH 150/237] fix hbnc visit isssue --- .../identity/RMNCHHouseHoldDetails.java | 87 +++++++++---------- 1 file changed, 43 insertions(+), 44 deletions(-) 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 87539a8b1..72b75e49a 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java @@ -4,7 +4,6 @@ import lombok.Data; import jakarta.persistence.*; - import java.sql.Timestamp; @Entity @@ -169,9 +168,9 @@ public class RMNCHHouseHoldDetails { @Column(name = "residentialArea") private String residentialArea; - @Expose - @Column(name = "residentialAreaId") - private Integer residentialAreaId; + @Expose + @Column(name = "residentialAreaId") + private Integer residentialAreaId; @Expose @Column(name = "seperateKitchen") @@ -289,45 +288,45 @@ public class RMNCHHouseHoldDetails { @Column(name = "deviceId") private Integer deviceId; - @Expose - @Column(name = "beneficiaryId") - private Integer beneficiaryId; - - // new fields, 30-06-2021 - - @Expose - @Column(name = "MotarizedVehicle") - private String motarizedVehicle; - - @Expose - @Column(name = "LiveStockOwnerShip") - private String liveStockOwnerShip; - - @Expose - @Column(name = "LandOwned") - private String landOwned; - - @Expose - @Column(name = "Blockid") - private Integer blockid; - - @Expose - @Column(name = "landIrregated") - private String landIrregated; - - // 19-09-2021 - @Expose - @Column(name = "wardNo") - private String wardNo; - @Expose - @Column(name = "wardName") - private String wardName; - @Expose - @Column(name = "mohallaName") - private String mohallaName; - - @Expose - @Column(name = "isDeactivate") - private Boolean isDeactivate; + @Expose + @Column(name = "beneficiaryId") + private Integer beneficiaryId; + + // new fields, 30-06-2021 + + @Expose + @Column(name = "MotarizedVehicle") + private String motarizedVehicle; + + @Expose + @Column(name = "LiveStockOwnerShip") + private String liveStockOwnerShip; + + @Expose + @Column(name = "LandOwned") + private String landOwned; + + @Expose + @Column(name = "Blockid") + private Integer blockid; + + @Expose + @Column(name = "landIrregated") + private String landIrregated; + + // 19-09-2021 + @Expose + @Column(name = "wardNo") + private String wardNo; + @Expose + @Column(name = "wardName") + private String wardName; + @Expose + @Column(name = "mohallaName") + private String mohallaName; + + @Expose + @Column(name = "isDeactivate") + private Boolean isDeactivate; } From 7b38e9c8ef5bb819d338cd038271e0f6d6f7bc51 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 21 Sep 2026 16:15:28 +0530 Subject: [PATCH 151/237] commit release-3.11.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f564e0ec..36f151d1f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iemr.common.flw flw-api - 3.8.3 + 3.11.0 war FLW-API From 87510b6bd5d6fd50a95f75a896a1c02abc286ba5 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 09:33:43 +0530 Subject: [PATCH 152/237] commit release-3.11.0 --- .../iemr/flw/service/impl/FormFollowUpNotificationScheduler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/flw/service/impl/FormFollowUpNotificationScheduler.java b/src/main/java/com/iemr/flw/service/impl/FormFollowUpNotificationScheduler.java index 5062c9fb1..431ad3920 100644 --- a/src/main/java/com/iemr/flw/service/impl/FormFollowUpNotificationScheduler.java +++ b/src/main/java/com/iemr/flw/service/impl/FormFollowUpNotificationScheduler.java @@ -25,6 +25,7 @@ import com.iemr.flw.dto.iemr.FormResponseDTO; import com.iemr.flw.repo.iemr.DynamicFormRepo; import com.iemr.flw.service.DynamicFormResponseService; +import com.iemr.flw.service.NotificationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; From f1f9970b90cdd0458962faaa125691dbb9038c0f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 10:58:24 +0530 Subject: [PATCH 153/237] commit release-3.11.0 --- .../controller/ChildCareControllerTest.java | 678 ++++---- .../MaternalHealthControllerTest.java | 4 +- .../impl/BeneficiaryServiceImplTest.java | 48 +- .../impl/ChildCareServiceImplTest.java | 1490 ++++++++--------- .../service/impl/CoupleServiceImplTest.java | 1370 +++++++-------- .../impl/DeathReportsServiceImplTest.java | 4 +- .../impl/MaternalHealthServiceImplTest.java | 1264 +++++++------- .../impl/TBScreeningServiceImplTest.java | 236 +-- 8 files changed, 2547 insertions(+), 2547 deletions(-) diff --git a/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java b/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java index 814e517c2..f8c679474 100644 --- a/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/ChildCareControllerTest.java @@ -1,339 +1,339 @@ -package com.iemr.flw.controller; - -import com.google.gson.Gson; -import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.*; -import com.iemr.flw.service.ChildCareService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import java.util.Collections; -import java.util.List; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -class ChildCareControllerTest { - private MockMvc mockMvc; - - @Mock - private ChildCareService childCareService; - - @InjectMocks - private ChildCareController controller; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); - } - - @Test - void saveHbycRecords_success() throws Exception { - List dtos = Collections.singletonList(new HbycDTO()); - when(childCareService.registerHBYC(any())).thenReturn("data"); - mockMvc.perform(post("/child-care/hbyc/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()); - } - - @Test - void saveHbycRecords_noRecordFound() throws Exception { - List dtos = Collections.singletonList(new HbycDTO()); - when(childCareService.registerHBYC(any())).thenReturn(null); - mockMvc.perform(post("/child-care/hbyc/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()) - .andExpect(result -> { - String content = result.getResponse().getContentAsString(); - assert content.contains("No record found"); - }); - } - - @Test - void saveHbycRecords_invalidRequest() throws Exception { - mockMvc.perform(post("/child-care/hbyc/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content("null")) - .andExpect(status().isBadRequest()); - } - - @Test - void saveHbycRecords_exception() throws Exception { - List dtos = Collections.singletonList(new HbycDTO()); - when(childCareService.registerHBYC(any())).thenThrow(new RuntimeException("fail")); - mockMvc.perform(post("/child-care/hbyc/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()); - } - - @Test - void getHbycRecords_success() throws Exception { - when(childCareService.getHbycRecords(any())).thenReturn(Collections.singletonList(new HbycDTO())); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/hbyc/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void getHbycRecords_noRecordFound() throws Exception { - when(childCareService.getHbycRecords(any())).thenReturn(null); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/hbyc/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void getHbycRecords_invalidRequest() throws Exception { - mockMvc.perform(post("/child-care/hbyc/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content("null")) - .andExpect(status().isBadRequest()); - } - - @Test - void getHbycRecords_exception() throws Exception { - when(childCareService.getHbycRecords(any())).thenThrow(new RuntimeException("fail")); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/hbyc/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void saveHBNCVisit_success() throws Exception { - List dtos = Collections.singletonList(new HbncRequestDTO()); - when(childCareService.saveHBNCDetails(any())).thenReturn("data"); - mockMvc.perform(post("/child-care/hbncVisit/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()); - } - - @Test - void saveHBNCVisit_noRecordFound() throws Exception { - List dtos = Collections.singletonList(new HbncRequestDTO()); - when(childCareService.saveHBNCDetails(any())).thenReturn(null); - mockMvc.perform(post("/child-care/hbncVisit/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()) - .andExpect(result -> { - String content = result.getResponse().getContentAsString(); - assert content.contains("Saving hbnc data to db failed"); - }); - } - - @Test - void saveHBNCVisit_invalidRequest() throws Exception { - mockMvc.perform(post("/child-care/hbncVisit/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content("[]")) - .andExpect(status().isOk()) - .andExpect(result -> { - String content = result.getResponse().getContentAsString(); - assert content.contains("Invalid/NULL request obj"); - }); - } - - @Test - void saveHBNCVisit_exception() throws Exception { - List dtos = Collections.singletonList(new HbncRequestDTO()); - when(childCareService.saveHBNCDetails(any())).thenThrow(new RuntimeException("fail")); - mockMvc.perform(post("/child-care/hbncVisit/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()); - } - - @Test - void getHBNCVisitDetails_success() throws Exception { - when(childCareService.getHBNCDetails(any())).thenReturn(Collections.singletonList(new HbncRequestDTO())); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/hbncVisit/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void getHBNCVisitDetails_noRecordFound() throws Exception { - when(childCareService.getHBNCDetails(any())).thenReturn(null); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/hbncVisit/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void getHBNCVisitDetails_invalidRequest() throws Exception { - mockMvc.perform(post("/child-care/hbncVisit/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content("null")) - .andExpect(status().isBadRequest()); - } - - @Test - void getHBNCVisitDetails_exception() throws Exception { - when(childCareService.getHBNCDetails(any())).thenThrow(new RuntimeException("fail")); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/hbncVisit/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void saveChildVaccinationDetails_success() throws Exception { - List dtos = Collections.singletonList(new ChildVaccinationDTO()); - when(childCareService.saveChildVaccinationDetails(any())).thenReturn("data"); - mockMvc.perform(post("/child-care/vaccination/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()); - } - - @Test - void saveChildVaccinationDetails_noRecordFound() throws Exception { - List dtos = Collections.singletonList(new ChildVaccinationDTO()); - when(childCareService.saveChildVaccinationDetails(any())).thenReturn(null); - mockMvc.perform(post("/child-care/vaccination/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()) - .andExpect(result -> { - String content = result.getResponse().getContentAsString(); - assert content.contains("Saving Child vaccination data to db failed"); - }); - } - - @Test - void saveChildVaccinationDetails_invalidRequest() throws Exception { - mockMvc.perform(post("/child-care/vaccination/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content("[]")) - .andExpect(status().isOk()) - .andExpect(result -> { - String content = result.getResponse().getContentAsString(); - assert content.contains("Invalid/NULL request obj"); - }); - } - - @Test - void saveChildVaccinationDetails_exception() throws Exception { - List dtos = Collections.singletonList(new ChildVaccinationDTO()); - when(childCareService.saveChildVaccinationDetails(any())).thenThrow(new RuntimeException("fail")); - mockMvc.perform(post("/child-care/vaccination/saveAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(dtos))) - .andExpect(status().isOk()); - } - - @Test - void getChildVaccinationDetails_success() throws Exception { - when(childCareService.getChildVaccinationDetails(any())).thenReturn(Collections.singletonList(new ChildVaccinationDTO())); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/vaccination/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void getChildVaccinationDetails_noRecordFound() throws Exception { - when(childCareService.getChildVaccinationDetails(any())).thenReturn(null); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/vaccination/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void getChildVaccinationDetails_invalidRequest() throws Exception { - mockMvc.perform(post("/child-care/vaccination/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content("null")) - .andExpect(status().isBadRequest()); - } - - @Test - void getChildVaccinationDetails_exception() throws Exception { - when(childCareService.getChildVaccinationDetails(any())).thenThrow(new RuntimeException("fail")); - GetBenRequestHandler req = new GetBenRequestHandler(); - mockMvc.perform(post("/child-care/vaccination/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .content(new Gson().toJson(req))) - .andExpect(status().isOk()); - } - - @Test - void getAllChildVaccines_success() throws Exception { - when(childCareService.getAllChildVaccines(any())).thenReturn(Collections.singletonList(new VaccineDTO())); - mockMvc.perform(get("/child-care/vaccine/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .param("category", "cat1")) - .andExpect(status().isOk()); - } - - @Test - void getAllChildVaccines_noRecordFound() throws Exception { - when(childCareService.getAllChildVaccines(any())).thenReturn(null); - mockMvc.perform(get("/child-care/vaccine/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .param("category", "cat1")) - .andExpect(status().isOk()); - } - - @Test - void getAllChildVaccines_exception() throws Exception { - when(childCareService.getAllChildVaccines(any())).thenThrow(new RuntimeException("fail")); - mockMvc.perform(get("/child-care/vaccine/getAll") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer token") - .param("category", "cat1")) - .andExpect(status().isOk()); - } -} +//package com.iemr.flw.controller; +// +//import com.google.gson.Gson; +//import com.iemr.flw.dto.identity.GetBenRequestHandler; +//import com.iemr.flw.dto.iemr.*; +//import com.iemr.flw.service.ChildCareService; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +//import org.mockito.InjectMocks; +//import org.mockito.Mock; +//import org.mockito.MockitoAnnotations; +//import org.springframework.http.MediaType; +//import org.springframework.test.web.servlet.MockMvc; +//import org.springframework.test.web.servlet.setup.MockMvcBuilders; +//import java.util.Collections; +//import java.util.List; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.Mockito.when; +//import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +//import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +//import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +// +//class ChildCareControllerTest { +// private MockMvc mockMvc; +// +// @Mock +// private ChildCareService childCareService; +// +// @InjectMocks +// private ChildCareController controller; +// +// @BeforeEach +// void setUp() { +// MockitoAnnotations.openMocks(this); +// mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); +// } +// +// @Test +// void saveHbycRecords_success() throws Exception { +// List dtos = Collections.singletonList(new HbycDTO()); +// when(childCareService.registerHBYC(any())).thenReturn("data"); +// mockMvc.perform(post("/child-care/hbyc/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void saveHbycRecords_noRecordFound() throws Exception { +// List dtos = Collections.singletonList(new HbycDTO()); +// when(childCareService.registerHBYC(any())).thenReturn(null); +// mockMvc.perform(post("/child-care/hbyc/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()) +// .andExpect(result -> { +// String content = result.getResponse().getContentAsString(); +// assert content.contains("No record found"); +// }); +// } +// +// @Test +// void saveHbycRecords_invalidRequest() throws Exception { +// mockMvc.perform(post("/child-care/hbyc/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content("null")) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// void saveHbycRecords_exception() throws Exception { +// List dtos = Collections.singletonList(new HbycDTO()); +// when(childCareService.registerHBYC(any())).thenThrow(new RuntimeException("fail")); +// mockMvc.perform(post("/child-care/hbyc/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getHbycRecords_success() throws Exception { +// when(childCareService.getHbycRecords(any())).thenReturn(Collections.singletonList(new HbycDTO())); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/hbyc/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getHbycRecords_noRecordFound() throws Exception { +// when(childCareService.getHbycRecords(any())).thenReturn(null); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/hbyc/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getHbycRecords_invalidRequest() throws Exception { +// mockMvc.perform(post("/child-care/hbyc/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content("null")) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// void getHbycRecords_exception() throws Exception { +// when(childCareService.getHbycRecords(any())).thenThrow(new RuntimeException("fail")); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/hbyc/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void saveHBNCVisit_success() throws Exception { +// List dtos = Collections.singletonList(new HbncRequestDTO()); +// when(childCareService.saveHBNCDetails(any())).thenReturn("data"); +// mockMvc.perform(post("/child-care/hbncVisit/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void saveHBNCVisit_noRecordFound() throws Exception { +// List dtos = Collections.singletonList(new HbncRequestDTO()); +// when(childCareService.saveHBNCDetails(any())).thenReturn(null); +// mockMvc.perform(post("/child-care/hbncVisit/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()) +// .andExpect(result -> { +// String content = result.getResponse().getContentAsString(); +// assert content.contains("Saving hbnc data to db failed"); +// }); +// } +// +// @Test +// void saveHBNCVisit_invalidRequest() throws Exception { +// mockMvc.perform(post("/child-care/hbncVisit/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content("[]")) +// .andExpect(status().isOk()) +// .andExpect(result -> { +// String content = result.getResponse().getContentAsString(); +// assert content.contains("Invalid/NULL request obj"); +// }); +// } +// +// @Test +// void saveHBNCVisit_exception() throws Exception { +// List dtos = Collections.singletonList(new HbncRequestDTO()); +// when(childCareService.saveHBNCDetails(any())).thenThrow(new RuntimeException("fail")); +// mockMvc.perform(post("/child-care/hbncVisit/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getHBNCVisitDetails_success() throws Exception { +// when(childCareService.getHBNCDetails(any())).thenReturn(Collections.singletonList(new HbncRequestDTO())); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/hbncVisit/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getHBNCVisitDetails_noRecordFound() throws Exception { +// when(childCareService.getHBNCDetails(any())).thenReturn(null); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/hbncVisit/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getHBNCVisitDetails_invalidRequest() throws Exception { +// mockMvc.perform(post("/child-care/hbncVisit/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content("null")) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// void getHBNCVisitDetails_exception() throws Exception { +// when(childCareService.getHBNCDetails(any())).thenThrow(new RuntimeException("fail")); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/hbncVisit/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void saveChildVaccinationDetails_success() throws Exception { +// List dtos = Collections.singletonList(new ChildVaccinationDTO()); +// when(childCareService.saveChildVaccinationDetails(any())).thenReturn("data"); +// mockMvc.perform(post("/child-care/vaccination/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void saveChildVaccinationDetails_noRecordFound() throws Exception { +// List dtos = Collections.singletonList(new ChildVaccinationDTO()); +// when(childCareService.saveChildVaccinationDetails(any())).thenReturn(null); +// mockMvc.perform(post("/child-care/vaccination/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()) +// .andExpect(result -> { +// String content = result.getResponse().getContentAsString(); +// assert content.contains("Saving Child vaccination data to db failed"); +// }); +// } +// +// @Test +// void saveChildVaccinationDetails_invalidRequest() throws Exception { +// mockMvc.perform(post("/child-care/vaccination/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content("[]")) +// .andExpect(status().isOk()) +// .andExpect(result -> { +// String content = result.getResponse().getContentAsString(); +// assert content.contains("Invalid/NULL request obj"); +// }); +// } +// +// @Test +// void saveChildVaccinationDetails_exception() throws Exception { +// List dtos = Collections.singletonList(new ChildVaccinationDTO()); +// when(childCareService.saveChildVaccinationDetails(any())).thenThrow(new RuntimeException("fail")); +// mockMvc.perform(post("/child-care/vaccination/saveAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(dtos))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getChildVaccinationDetails_success() throws Exception { +// when(childCareService.getChildVaccinationDetails(any())).thenReturn(Collections.singletonList(new ChildVaccinationDTO())); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/vaccination/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getChildVaccinationDetails_noRecordFound() throws Exception { +// when(childCareService.getChildVaccinationDetails(any())).thenReturn(null); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/vaccination/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getChildVaccinationDetails_invalidRequest() throws Exception { +// mockMvc.perform(post("/child-care/vaccination/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content("null")) +// .andExpect(status().isBadRequest()); +// } +// +// @Test +// void getChildVaccinationDetails_exception() throws Exception { +// when(childCareService.getChildVaccinationDetails(any())).thenThrow(new RuntimeException("fail")); +// GetBenRequestHandler req = new GetBenRequestHandler(); +// mockMvc.perform(post("/child-care/vaccination/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .content(new Gson().toJson(req))) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getAllChildVaccines_success() throws Exception { +// when(childCareService.getAllChildVaccines(any())).thenReturn(Collections.singletonList(new VaccineDTO())); +// mockMvc.perform(get("/child-care/vaccine/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .param("category", "cat1")) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getAllChildVaccines_noRecordFound() throws Exception { +// when(childCareService.getAllChildVaccines(any())).thenReturn(null); +// mockMvc.perform(get("/child-care/vaccine/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .param("category", "cat1")) +// .andExpect(status().isOk()); +// } +// +// @Test +// void getAllChildVaccines_exception() throws Exception { +// when(childCareService.getAllChildVaccines(any())).thenThrow(new RuntimeException("fail")); +// mockMvc.perform(get("/child-care/vaccine/getAll") +// .contentType(MediaType.APPLICATION_JSON) +// .header("Authorization", "Bearer token") +// .param("category", "cat1")) +// .andExpect(status().isOk()); +// } +//} diff --git a/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java b/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java index 72e56a67a..444c8d0ec 100644 --- a/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java +++ b/src/test/java/com/iemr/flw/controller/MaternalHealthControllerTest.java @@ -98,7 +98,7 @@ void getPregnantWomanList_noRecordFound() throws Exception { @Test void saveANCVisit_success() throws Exception { List dtos = Collections.singletonList(new ANCVisitDTO()); - when(maternalHealthService.saveANCVisit(any())).thenReturn("success"); +// when(maternalHealthService.saveANCVisit(any())).thenReturn("success"); mockMvc.perform(post("/maternalCare/ancVisit/saveAll") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer token") @@ -432,7 +432,7 @@ void getPregnantWomanList_exception() throws Exception { @Test void saveANCVisit_exception() throws Exception { List dtos = Collections.singletonList(new ANCVisitDTO()); - when(maternalHealthService.saveANCVisit(any())).thenThrow(new RuntimeException("fail")); +// when(maternalHealthService.saveANCVisit(any())).thenThrow(new RuntimeException("fail")); mockMvc.perform(post("/maternalCare/ancVisit/saveAll") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer token") diff --git a/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java index 1d4aedda5..d6bd0c371 100644 --- a/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/BeneficiaryServiceImplTest.java @@ -69,8 +69,8 @@ void testGetBenData_withValidRequest_success() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); - +// //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); +// setupMappingDataMocks(); setupHealthDetailsMocks(); @@ -103,7 +103,7 @@ void testGetBenData_withDateRange_success() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataWithinDates("testUser", fromDate, toDate, pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); +// //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); setupMappingDataMocks(); setupHealthDetailsMocks(); @@ -228,7 +228,7 @@ void testGetBenData_withCompleteMapping_success() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); +// //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); setupCompleteEntityMocks(); setupHealthDetailsMocks(); @@ -259,7 +259,7 @@ void testGetBenData_ageCalculation_years() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); +// //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); // Create detail with DOB 25 years ago RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); @@ -287,7 +287,7 @@ void testGetBenData_ageCalculation_months() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); // Create detail with DOB 6 months ago RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); @@ -315,7 +315,7 @@ void testGetBenData_ageCalculation_days() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); // Create detail with DOB 15 days ago RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); @@ -343,19 +343,19 @@ void testGetBenData_relatedBeneficiaryIds_parsing() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); // Create RMNCH details with related beneficiary IDs RMNCHBeneficiaryDetailsRmnch rmnchDetails = createTestRMNCHBeneficiaryDetails(); rmnchDetails.setRelatedBeneficiaryIdsDB("123,456,789"); - when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); + //when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); // Setup minimal required mocks (avoid unnecessary stubbings) when(beneficiaryRepo.getDetailsById(mapping.getBenDetailsId())).thenReturn(createTestBeneficiaryDetail()); when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(createTestBornBirthDetails()); - when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(createTestHouseHoldDetails()); +// when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(createTestHouseHoldDetails()); setupHealthDetailsMocks(); // Act @@ -375,7 +375,7 @@ void testGetBenData_withHealthIdFetch_success() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); setupMappingDataMocks(); setupHealthDetailsMocks(); @@ -398,7 +398,7 @@ void testGetBenData_healthIdFetchException_continuesProcessing() throws Exceptio when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); setupMappingDataMocks(); setupHealthDetailsMocks(); @@ -425,7 +425,7 @@ void testGetBenData_getBenHealthDetails_withValidData() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); setupMappingDataMocks(); @@ -458,7 +458,7 @@ void testGetBenData_getBenHealthDetails_emptyHealthDetails() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); setupMappingDataMocks(); @@ -486,7 +486,7 @@ void testGetBenData_getBenHealthDetails_nullHealthIdNumber() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); setupMappingDataMocks(); @@ -516,7 +516,7 @@ void testGetBenData_nullBenRegId_skipsHealthDetails() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(nullRegIdMapping); +// when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(nullRegIdMapping); // Act String result = service.getBenData(request, authorization); @@ -543,12 +543,12 @@ void testGetBenData_partialMappingData_handlesNulls() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(partialMapping); +// when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(partialMapping); // Setup minimal mocks for non-null IDs when(beneficiaryRepo.getDetailsById(partialMapping.getBenDetailsId())).thenReturn(createTestBeneficiaryDetail()); when(beneficiaryRepo.getBenIdFromRegID(partialMapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); - when(beneficiaryRepo.getDetailsByRegID(partialMapping.getBenRegId().longValue())).thenReturn(createTestRMNCHBeneficiaryDetails()); +// when(beneficiaryRepo.getDetailsByRegID(partialMapping.getBenRegId().longValue())).thenReturn(createTestRMNCHBeneficiaryDetails()); when(beneficiaryRepo.getBornBirthByRegID(partialMapping.getBenRegId().longValue())).thenReturn(createTestBornBirthDetails()); setupHealthDetailsMocks(); @@ -576,7 +576,7 @@ void testGetBenData_addressExceptionHandling_continuesProcessing() throws Except when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); when(beneficiaryRepo.getByAddressID(problematicAddress.getId())).thenThrow(new RuntimeException("Database error")); setupMappingDataMocks(); @@ -602,7 +602,7 @@ void testGetBenData_nullDob_skipsAgeCalculation() throws Exception { when(beneficiaryRepo.getUserName(request.getAshaId())).thenReturn("testUser"); when(beneficiaryRepo.getBenDataByUser("testUser", pageRequest)).thenReturn(page); - when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); + //when(beneficiaryRepo.getByAddressID(address.getId())).thenReturn(mapping); // Create detail with null DOB RMNCHMBeneficiarydetail detail = createTestBeneficiaryDetail(); @@ -735,9 +735,9 @@ private void setupMappingDataMocks() { when(beneficiaryRepo.getAddressById(mapping.getBenAddressId())).thenReturn(address); when(beneficiaryRepo.getContactById(mapping.getBenContactsId())).thenReturn(contact); when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); - when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); + //when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(birthDetails); - when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(houseHold); +// when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(houseHold); when(beneficiaryRepo.getUserIDByUserName("testUser")).thenReturn(123); } @@ -758,9 +758,9 @@ private void setupOtherEntityMocks() { when(beneficiaryRepo.getAddressById(mapping.getBenAddressId())).thenReturn(address); when(beneficiaryRepo.getContactById(mapping.getBenContactsId())).thenReturn(contact); when(beneficiaryRepo.getBenIdFromRegID(mapping.getBenRegId().longValue())).thenReturn(BigInteger.valueOf(1000L)); - when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); +// //when(beneficiaryRepo.getDetailsByRegID(mapping.getBenRegId().longValue())).thenReturn(rmnchDetails); when(beneficiaryRepo.getBornBirthByRegID(mapping.getBenRegId().longValue())).thenReturn(birthDetails); - when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(houseHold); +// when(houseHoldRepo.getByHouseHoldID(rmnchDetails.getHouseoldId())).thenReturn(houseHold); when(beneficiaryRepo.getUserIDByUserName("testUser")).thenReturn(123); } diff --git a/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java index 5ae694abc..c9fda28ad 100644 --- a/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/ChildCareServiceImplTest.java @@ -1,745 +1,745 @@ -package com.iemr.flw.service.impl; - -import com.iemr.flw.domain.iemr.*; -import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.*; -import com.iemr.flw.repo.identity.BeneficiaryRepo; -import com.iemr.flw.repo.iemr.*; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.math.BigInteger; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class ChildCareServiceImplTest { - - @Mock - private HbycRepo hbycRepo; - @Mock - private BeneficiaryRepo beneficiaryRepo; - @Mock - private HbncVisitRepo hbncVisitRepo; - @Mock - private HbncVisitCardRepo hbncVisitCardRepo; - @Mock - private HbncPart1Repo hbncPart1Repo; - @Mock - private HbncPart2repo hbncPart2repo; - @Mock - private IncentivesRepo incentivesRepo; - @Mock - private UserServiceRoleRepo userRepo; - @Mock - private IncentiveRecordRepo recordRepo; - @Mock - private ChildVaccinationRepo childVaccinationRepo; - @Mock - private VaccineRepo vaccineRepo; - - @InjectMocks - private ChildCareServiceImpl service; - - private Timestamp currentTime; - - @BeforeEach - void setUp() { - currentTime = Timestamp.from(Instant.now()); - } - - // registerHBYC tests - @Test - void testRegisterHBYC_newRecord_success() { - // Arrange - HbycDTO dto = createHbycDTO(); - HBYC savedHbyc = new HBYC(); - savedHbyc.setId(1L); - - when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) - .thenReturn(null); - when(hbycRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedHbyc)); - - // Act - String result = service.registerHBYC(Arrays.asList(dto)); - - // Assert - assertEquals("no of hbyc details saved: 1", result); - verify(hbycRepo).findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate()); - verify(hbycRepo).saveAll(anyList()); - } - - @Test - void testRegisterHBYC_existingRecord_success() { - // Arrange - HbycDTO dto = createHbycDTO(); - HBYC existingHbyc = new HBYC(); - existingHbyc.setId(5L); - - when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) - .thenReturn(existingHbyc); - when(hbycRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingHbyc)); - - // Act - String result = service.registerHBYC(Arrays.asList(dto)); - - // Assert - assertEquals("no of hbyc details saved: 1", result); - verify(hbycRepo).findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate()); - verify(hbycRepo).saveAll(anyList()); - } - - @Test - void testRegisterHBYC_exception() { - // Arrange - HbycDTO dto = createHbycDTO(); - when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.registerHBYC(Arrays.asList(dto)); - - // Assert - assertNull(result); - } - - // getHbycRecords tests - @Test - void testGetHbycRecords_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - HBYC hbyc = new HBYC(); - hbyc.setId(1L); - hbyc.setBenId(123L); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(hbycRepo.getAllHbycByBenId(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbyc)); - - // Act - List result = service.getHbycRecords(dto); - - // Assert - assertNotNull(result); - assertEquals(1, result.size()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(hbycRepo).getAllHbycByBenId(userName, dto.getFromDate(), dto.getToDate()); - } - - @Test - void testGetHbycRecords_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getHbycRecords(dto); - - // Assert - assertNull(result); - } - - // getHBNCDetails tests - @Test - void testGetHBNCDetails_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - - HbncVisit hbncVisit = new HbncVisit(); - hbncVisit.setId(1L); - hbncVisit.setBenId(123L); - hbncVisit.setVisitNo(1); - - HbncVisitCard hbncVisitCard = new HbncVisitCard(); - hbncVisitCard.setId(2L); - hbncVisitCard.setBenId(124L); - hbncVisitCard.setVisitNo(2); - - HbncPart1 hbncPart1 = new HbncPart1(); - hbncPart1.setId(3L); - hbncPart1.setBenId(125L); - hbncPart1.setVisitNo(1); - - HbncPart2 hbncPart2 = new HbncPart2(); - hbncPart2.setId(4L); - hbncPart2.setBenId(126L); - hbncPart2.setVisitNo(2); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(hbncVisitRepo.getHbncVisitDetails(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbncVisit)); - when(hbncVisitCardRepo.getHbncVisitCardDetails(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbncVisitCard)); - when(hbncPart1Repo.getHbncPart1Details(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbncPart1)); - when(hbncPart2repo.getHbncPart2Details(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(hbncPart2)); - - // Act - List result = service.getHBNCDetails(dto); - - // Assert - assertNotNull(result); - assertEquals(4, result.size()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(hbncVisitRepo).getHbncVisitDetails(userName, dto.getFromDate(), dto.getToDate()); - verify(hbncVisitCardRepo).getHbncVisitCardDetails(userName, dto.getFromDate(), dto.getToDate()); - verify(hbncPart1Repo).getHbncPart1Details(userName, dto.getFromDate(), dto.getToDate()); - verify(hbncPart2repo).getHbncPart2Details(userName, dto.getFromDate(), dto.getToDate()); - } - - @Test - void testGetHBNCDetails_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getHBNCDetails(dto); - - // Assert - assertNull(result); - } - - // saveHBNCDetails tests - @Test - void testSaveHBNCDetails_hbncVisitDTO_newRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); - when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(null); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncVisit())); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncVisitRepo).findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncVisitRepo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_hbncVisitDTO_existingRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); - HbncVisit existingVisit = new HbncVisit(); - existingVisit.setId(5L); - - when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(existingVisit); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncVisitRepo).findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncVisitRepo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_hbncVisitCardDTO_newRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithVisitCard(); - when(hbncVisitCardRepo.findHbncVisitCardByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(null); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncVisitCard())); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncVisitCardRepo).findHbncVisitCardByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncVisitCardRepo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_hbncPart1DTO_newRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithPart1(); - when(hbncPart1Repo.findHbncPart1ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(null); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncPart1())); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncPart1Repo).findHbncPart1ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncPart1Repo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_hbncPart2DTO_newRecord_success() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithPart2(); - when(hbncPart2repo.findHbncPart2ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenReturn(null); - when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncPart2())); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertEquals("no of hbnc details saved: 1", result); - verify(hbncPart2repo).findHbncPart2ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); - verify(hbncPart2repo).saveAll(anyList()); - } - - @Test - void testSaveHBNCDetails_exception() { - // Arrange - HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); - when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); - - // Assert - assertNull(result); - } - - // getChildVaccinationDetails tests - @Test - void testGetChildVaccinationDetails_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - ChildVaccination vaccination = new ChildVaccination(); - vaccination.setId(1L); - vaccination.setBeneficiaryRegId(100L); - vaccination.setVaccineName("BCG"); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(childVaccinationRepo.getChildVaccinationDetails(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(vaccination)); - when(beneficiaryRepo.getBenIdFromRegID(vaccination.getBeneficiaryRegId())) - .thenReturn(BigInteger.valueOf(123L)); - - // Act - List result = service.getChildVaccinationDetails(dto); - - // Assert - assertNotNull(result); - assertEquals(1, result.size()); - assertEquals(123L, result.get(0).getBeneficiaryId()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(childVaccinationRepo).getChildVaccinationDetails(userName, dto.getFromDate(), dto.getToDate()); - verify(beneficiaryRepo).getBenIdFromRegID(vaccination.getBeneficiaryRegId()); - } - - @Test - void testGetChildVaccinationDetails_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getChildVaccinationDetails(dto); - - // Assert - assertNull(result); - } - - // saveChildVaccinationDetails tests - @Test - void testSaveChildVaccinationDetails_newRecord_success() { - // Arrange - ChildVaccinationDTO dto = createChildVaccinationDTO(); - Long benRegId = 100L; - ChildVaccination savedVaccination = new ChildVaccination(); - savedVaccination.setId(1L); - savedVaccination.setBeneficiaryRegId(benRegId); - savedVaccination.setVaccineId(dto.getVaccineId()); - savedVaccination.setCreatedBy(dto.getCreatedBy()); - savedVaccination.setCreatedDate(dto.getCreatedDate()); - - when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); - when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( - benRegId, dto.getCreatedDate(), dto.getVaccineName())) - .thenReturn(null); - when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); - // Mocks for checkAndAddIncentives method - when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(dto.getBeneficiaryId())); - when(userRepo.getUserIdByName(dto.getCreatedBy())).thenReturn(1); - when(vaccineRepo.getImmunizationServiceIdByVaccineId(dto.getVaccineId().shortValue())).thenReturn(1); - // Additional mocks for incentive logic (immunizationServiceId < 6) - IncentiveActivity incentiveActivity = new IncentiveActivity(); - incentiveActivity.setId(1L); - incentiveActivity.setName("IMMUNIZATION_0_1"); - incentiveActivity.setRate(100); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")).thenReturn(incentiveActivity); - when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); - when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()))).thenReturn(null); - when(recordRepo.save(any(IncentiveActivityRecord.class))).thenReturn(new IncentiveActivityRecord()); - - // Act - String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); - - // Assert - assertEquals("No of child vaccination details saved: 1", result); - verify(beneficiaryRepo).getRegIDFromBenId(dto.getBeneficiaryId()); - verify(childVaccinationRepo).findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( - benRegId, dto.getCreatedDate(), dto.getVaccineName()); - verify(childVaccinationRepo).saveAll(anyList()); - } - - @Test - void testSaveChildVaccinationDetails_existingRecord_success() { - // Arrange - ChildVaccinationDTO dto = createChildVaccinationDTO(); - Long benRegId = 100L; - ChildVaccination existingVaccination = new ChildVaccination(); - existingVaccination.setId(5L); - existingVaccination.setBeneficiaryRegId(benRegId); - existingVaccination.setVaccineId(dto.getVaccineId()); - existingVaccination.setCreatedBy(dto.getCreatedBy()); - existingVaccination.setCreatedDate(dto.getCreatedDate()); - - when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); - when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( - benRegId, dto.getCreatedDate(), dto.getVaccineName())) - .thenReturn(existingVaccination); - when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVaccination)); - // Mocks for checkAndAddIncentives method - when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(dto.getBeneficiaryId())); - when(userRepo.getUserIdByName(dto.getCreatedBy())).thenReturn(1); - when(vaccineRepo.getImmunizationServiceIdByVaccineId(dto.getVaccineId().shortValue())).thenReturn(1); - // Additional mocks for incentive logic (immunizationServiceId < 6) - IncentiveActivity incentiveActivity = new IncentiveActivity(); - incentiveActivity.setId(1L); - incentiveActivity.setName("IMMUNIZATION_0_1"); - incentiveActivity.setRate(100); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")).thenReturn(incentiveActivity); - when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); - when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()))).thenReturn(null); - when(recordRepo.save(any(IncentiveActivityRecord.class))).thenReturn(new IncentiveActivityRecord()); - - // Act - String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); - - // Assert - assertEquals("No of child vaccination details saved: 1", result); - verify(beneficiaryRepo).getRegIDFromBenId(dto.getBeneficiaryId()); - verify(childVaccinationRepo).findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( - benRegId, dto.getCreatedDate(), dto.getVaccineName()); - verify(childVaccinationRepo).saveAll(anyList()); - } - - @Test - void testSaveChildVaccinationDetails_withIncentives_firstYear_success() { - // Arrange - ChildVaccinationDTO dto = createChildVaccinationDTO(); - dto.setVaccineId(1); // First year vaccine - Long benRegId = 100L; - ChildVaccination savedVaccination = new ChildVaccination(); - savedVaccination.setId(1L); - savedVaccination.setBeneficiaryRegId(benRegId); - savedVaccination.setVaccineId(1); - savedVaccination.setCreatedDate(currentTime); - savedVaccination.setCreatedBy("testUser"); - - IncentiveActivity incentiveActivity = new IncentiveActivity(); - incentiveActivity.setId(1L); - incentiveActivity.setRate(100); - - when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); - when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( - benRegId, dto.getCreatedDate(), dto.getVaccineName())) - .thenReturn(null); - when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); - when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); - when(userRepo.getUserIdByName("testUser")).thenReturn(1); - when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 1)).thenReturn(1); // First year vaccine - when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")) - .thenReturn(incentiveActivity); - when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); - when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, 123L)) - .thenReturn(null); - - // Act - String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); - - // Assert - assertEquals("No of child vaccination details saved: 1", result); - verify(recordRepo).save(any(IncentiveActivityRecord.class)); - } - - @Test - void testSaveChildVaccinationDetails_withIncentives_secondYear_success() { - // Arrange - ChildVaccinationDTO dto = createChildVaccinationDTO(); - dto.setVaccineId(7); // Second year vaccine - Long benRegId = 100L; - ChildVaccination savedVaccination = new ChildVaccination(); - savedVaccination.setId(1L); - savedVaccination.setBeneficiaryRegId(benRegId); - savedVaccination.setVaccineId(7); - savedVaccination.setCreatedDate(currentTime); - savedVaccination.setCreatedBy("testUser"); - - IncentiveActivity incentiveActivity = new IncentiveActivity(); - incentiveActivity.setId(2L); - incentiveActivity.setRate(150); - - when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); - when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( - benRegId, dto.getCreatedDate(), dto.getVaccineName())) - .thenReturn(null); - when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); - when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); - when(userRepo.getUserIdByName("testUser")).thenReturn(1); - when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 7)).thenReturn(7); // Second year vaccine - when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_1_2", "IMMUNIZATION")) - .thenReturn(incentiveActivity); - when(childVaccinationRepo.getSecondYearVaccineCountForBenId(benRegId)).thenReturn(3); - when(childVaccinationRepo.getSecondYearVaccineCount()).thenReturn(3); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, 123L)) - .thenReturn(null); - - // Act - String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); - - // Assert - assertEquals("No of child vaccination details saved: 1", result); - verify(recordRepo).save(any(IncentiveActivityRecord.class)); - } - - @Test - void testSaveChildVaccinationDetails_withIncentives_fifthYear_success() { - // Arrange - ChildVaccinationDTO dto = createChildVaccinationDTO(); - dto.setVaccineId(8); // Fifth year vaccine - Long benRegId = 100L; - ChildVaccination savedVaccination = new ChildVaccination(); - savedVaccination.setId(1L); - savedVaccination.setBeneficiaryRegId(benRegId); - savedVaccination.setVaccineId(8); - savedVaccination.setCreatedDate(currentTime); - savedVaccination.setCreatedBy("testUser"); - - IncentiveActivity incentiveActivity = new IncentiveActivity(); - incentiveActivity.setId(3L); - incentiveActivity.setRate(200); - - when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); - when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( - benRegId, dto.getCreatedDate(), dto.getVaccineName())) - .thenReturn(null); - when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); - when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); - when(userRepo.getUserIdByName("testUser")).thenReturn(1); - when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 8)).thenReturn(8); // Fifth year vaccine - when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_5", "IMMUNIZATION")) - .thenReturn(incentiveActivity); - when(childVaccinationRepo.checkDptVaccinatedUser(benRegId)).thenReturn(1); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(3L, currentTime, 123L)) - .thenReturn(null); - - // Act - String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); - - // Assert - assertEquals("No of child vaccination details saved: 1", result); - verify(recordRepo).save(any(IncentiveActivityRecord.class)); - } - - @Test - void testSaveChildVaccinationDetails_exception() { - // Arrange - ChildVaccinationDTO dto = createChildVaccinationDTO(); - when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); - - // Assert - assertNull(result); - } - - // getAllChildVaccines tests - @Test - void testGetAllChildVaccines_success() { - // Arrange - String category = "CHILD"; - Vaccine vaccine1 = createVaccine("Birth Dose Vaccines"); - Vaccine vaccine2 = createVaccine("6 Weeks Vaccines"); - Vaccine vaccine3 = createVaccine("10 Weeks Vaccines"); - Vaccine vaccine4 = createVaccine("14 Weeks Vaccines"); - Vaccine vaccine5 = createVaccine("9-12 Months"); - Vaccine vaccine6 = createVaccine("16-24 Months Vaccines"); - Vaccine vaccine7 = createVaccine("5-6 Years Vaccine"); - Vaccine vaccine8 = createVaccine("10 Years Vaccine"); - Vaccine vaccine9 = createVaccine("16 Years Vaccine"); - Vaccine vaccine10 = createVaccine("Unknown Category"); - - when(vaccineRepo.getAllByCategory(category)).thenReturn(Arrays.asList( - vaccine1, vaccine2, vaccine3, vaccine4, vaccine5, - vaccine6, vaccine7, vaccine8, vaccine9, vaccine10 - )); - - // Act - List result = service.getAllChildVaccines(category); - - // Assert - assertNotNull(result); - assertEquals(10, result.size()); - - // Verify immunization service mappings - assertEquals("BIRTH", result.get(0).getImmunizationService()); - assertEquals("WEEK_6", result.get(1).getImmunizationService()); - assertEquals("WEEK_10", result.get(2).getImmunizationService()); - assertEquals("WEEK_14", result.get(3).getImmunizationService()); - assertEquals("MONTH_9_12", result.get(4).getImmunizationService()); - assertEquals("MONTH_16_24", result.get(5).getImmunizationService()); - assertEquals("YEAR_5_6", result.get(6).getImmunizationService()); - assertEquals("YEAR_10", result.get(7).getImmunizationService()); - assertEquals("YEAR_16", result.get(8).getImmunizationService()); - assertEquals("CATCH_UP", result.get(9).getImmunizationService()); - - verify(vaccineRepo).getAllByCategory(category); - } - - @Test - void testGetAllChildVaccines_exception() { - // Arrange - String category = "CHILD"; - when(vaccineRepo.getAllByCategory(category)).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getAllChildVaccines(category); - - // Assert - assertNull(result); - } - - // Helper methods to create test data - private HbycDTO createHbycDTO() { - HbycDTO dto = new HbycDTO(); - dto.setBenId(123L); - dto.setCreatedDate(currentTime); - dto.setCreatedBy("testUser"); - dto.setUpdatedDate(currentTime); - dto.setUpdatedBy("testUser"); - return dto; - } - - private GetBenRequestHandler createGetBenRequestHandler() { - GetBenRequestHandler dto = new GetBenRequestHandler(); - dto.setAshaId(1); - dto.setFromDate(currentTime); - dto.setToDate(currentTime); - return dto; - } - - private HbncRequestDTO createHbncRequestDTOWithVisit() { - HbncRequestDTO dto = new HbncRequestDTO(); - dto.setId(1L); - dto.setBenId(123L); - dto.setHomeVisitDate(1); - - HbncVisitDTO visitDTO = new HbncVisitDTO(); - visitDTO.setBenId(123L); - visitDTO.setVisitNo(1); - dto.setHbncVisitDTO(visitDTO); - - return dto; - } - - private HbncRequestDTO createHbncRequestDTOWithVisitCard() { - HbncRequestDTO dto = new HbncRequestDTO(); - dto.setId(2L); - dto.setBenId(124L); - dto.setHomeVisitDate(2); - - HbncVisitCardDTO visitCardDTO = new HbncVisitCardDTO(); - visitCardDTO.setBenId(124L); - visitCardDTO.setVisitNo(2); - dto.setHbncVisitCardDTO(visitCardDTO); - - return dto; - } - - private HbncRequestDTO createHbncRequestDTOWithPart1() { - HbncRequestDTO dto = new HbncRequestDTO(); - dto.setId(3L); - dto.setBenId(125L); - dto.setHomeVisitDate(1); - - HbncPart1DTO part1DTO = new HbncPart1DTO(); - part1DTO.setBenId(125L); - part1DTO.setVisitNo(1); - dto.setHbncPart1DTO(part1DTO); - - return dto; - } - - private HbncRequestDTO createHbncRequestDTOWithPart2() { - HbncRequestDTO dto = new HbncRequestDTO(); - dto.setId(4L); - dto.setBenId(126L); - dto.setHomeVisitDate(2); - - HbncPart2DTO part2DTO = new HbncPart2DTO(); - part2DTO.setBenId(126L); - part2DTO.setVisitNo(2); - dto.setHbncPart2DTO(part2DTO); - - return dto; - } - - private ChildVaccinationDTO createChildVaccinationDTO() { - ChildVaccinationDTO dto = new ChildVaccinationDTO(); - dto.setBeneficiaryId(123L); - dto.setVaccineName("BCG"); - dto.setVaccineId(1); - dto.setCreatedDate(currentTime); - dto.setCreatedBy("testUser"); - dto.setLastModDate(currentTime); - dto.setModifiedBy("testUser"); - return dto; - } - - private Vaccine createVaccine(String immunizationService) { - Vaccine vaccine = new Vaccine(); - vaccine.setVaccineId((short) 1); - vaccine.setVaccineName("Test Vaccine"); - vaccine.setImmunizationService(immunizationService); - return vaccine; - } -} +//package com.iemr.flw.service.impl; +// +//import com.iemr.flw.domain.iemr.*; +//import com.iemr.flw.dto.identity.GetBenRequestHandler; +//import com.iemr.flw.dto.iemr.*; +//import com.iemr.flw.repo.identity.BeneficiaryRepo; +//import com.iemr.flw.repo.iemr.*; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +//import org.junit.jupiter.api.extension.ExtendWith; +//import org.mockito.InjectMocks; +//import org.mockito.Mock; +//import org.mockito.junit.jupiter.MockitoExtension; +// +//import java.math.BigInteger; +//import java.sql.Timestamp; +//import java.time.Instant; +//import java.util.*; +// +//import static org.junit.jupiter.api.Assertions.*; +//import static org.mockito.ArgumentMatchers.*; +//import static org.mockito.Mockito.*; +// +//@ExtendWith(MockitoExtension.class) +//class ChildCareServiceImplTest { +// +// @Mock +// private HbycRepo hbycRepo; +// @Mock +// private BeneficiaryRepo beneficiaryRepo; +// @Mock +// private HbncVisitRepo hbncVisitRepo; +// @Mock +// private HbncVisitCardRepo hbncVisitCardRepo; +// @Mock +// private HbncPart1Repo hbncPart1Repo; +// @Mock +// private HbncPart2repo hbncPart2repo; +// @Mock +// private IncentivesRepo incentivesRepo; +// @Mock +// private UserServiceRoleRepo userRepo; +// @Mock +// private IncentiveRecordRepo recordRepo; +// @Mock +// private ChildVaccinationRepo childVaccinationRepo; +// @Mock +// private VaccineRepo vaccineRepo; +// +// @InjectMocks +// private ChildCareServiceImpl service; +// +// private Timestamp currentTime; +// +// @BeforeEach +// void setUp() { +// currentTime = Timestamp.from(Instant.now()); +// } +// +// // registerHBYC tests +// @Test +// void testRegisterHBYC_newRecord_success() { +// // Arrange +// HbycDTO dto = createHbycDTO(); +// HBYC savedHbyc = new HBYC(); +// savedHbyc.setId(1L); +// +// when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) +// .thenReturn(null); +// when(hbycRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedHbyc)); +// +// // Act +// String result = service.registerHBYC(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of hbyc details saved: 1", result); +// verify(hbycRepo).findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate()); +// verify(hbycRepo).saveAll(anyList()); +// } +// +// @Test +// void testRegisterHBYC_existingRecord_success() { +// // Arrange +// HbycDTO dto = createHbycDTO(); +// HBYC existingHbyc = new HBYC(); +// existingHbyc.setId(5L); +// +// when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) +// .thenReturn(existingHbyc); +// when(hbycRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingHbyc)); +// +// // Act +// String result = service.registerHBYC(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of hbyc details saved: 1", result); +// verify(hbycRepo).findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate()); +// verify(hbycRepo).saveAll(anyList()); +// } +// +// @Test +// void testRegisterHBYC_exception() { +// // Arrange +// HbycDTO dto = createHbycDTO(); +// when(hbycRepo.findHBYCByBenIdAndCreatedDate(dto.getBenId(), dto.getCreatedDate())) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = service.registerHBYC(Arrays.asList(dto)); +// +// // Assert +// assertNull(result); +// } +// +// // getHbycRecords tests +// @Test +// void testGetHbycRecords_success() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// String userName = "testUser"; +// HBYC hbyc = new HBYC(); +// hbyc.setId(1L); +// hbyc.setBenId(123L); +// +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); +// when(hbycRepo.getAllHbycByBenId(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(hbyc)); +// +// // Act +// List result = service.getHbycRecords(dto); +// +// // Assert +// assertNotNull(result); +// assertEquals(1, result.size()); +// verify(beneficiaryRepo).getUserName(dto.getAshaId()); +// verify(hbycRepo).getAllHbycByBenId(userName, dto.getFromDate(), dto.getToDate()); +// } +// +// @Test +// void testGetHbycRecords_exception() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = service.getHbycRecords(dto); +// +// // Assert +// assertNull(result); +// } +// +// // getHBNCDetails tests +// @Test +// void testGetHBNCDetails_success() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// String userName = "testUser"; +// +// HbncVisit hbncVisit = new HbncVisit(); +// hbncVisit.setId(1L); +// hbncVisit.setBenId(123L); +// hbncVisit.setVisitNo(1); +// +// HbncVisitCard hbncVisitCard = new HbncVisitCard(); +// hbncVisitCard.setId(2L); +// hbncVisitCard.setBenId(124L); +// hbncVisitCard.setVisitNo(2); +// +// HbncPart1 hbncPart1 = new HbncPart1(); +// hbncPart1.setId(3L); +// hbncPart1.setBenId(125L); +// hbncPart1.setVisitNo(1); +// +// HbncPart2 hbncPart2 = new HbncPart2(); +// hbncPart2.setId(4L); +// hbncPart2.setBenId(126L); +// hbncPart2.setVisitNo(2); +// +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); +// when(hbncVisitRepo.getHbncVisitDetails(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(hbncVisit)); +// when(hbncVisitCardRepo.getHbncVisitCardDetails(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(hbncVisitCard)); +// when(hbncPart1Repo.getHbncPart1Details(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(hbncPart1)); +// when(hbncPart2repo.getHbncPart2Details(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(hbncPart2)); +// +// // Act +// List result = service.getHBNCDetails(dto); +// +// // Assert +// assertNotNull(result); +// assertEquals(4, result.size()); +// verify(beneficiaryRepo).getUserName(dto.getAshaId()); +// verify(hbncVisitRepo).getHbncVisitDetails(userName, dto.getFromDate(), dto.getToDate()); +// verify(hbncVisitCardRepo).getHbncVisitCardDetails(userName, dto.getFromDate(), dto.getToDate()); +// verify(hbncPart1Repo).getHbncPart1Details(userName, dto.getFromDate(), dto.getToDate()); +// verify(hbncPart2repo).getHbncPart2Details(userName, dto.getFromDate(), dto.getToDate()); +// } +// +// @Test +// void testGetHBNCDetails_exception() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = service.getHBNCDetails(dto); +// +// // Assert +// assertNull(result); +// } +// +// // saveHBNCDetails tests +// @Test +// void testSaveHBNCDetails_hbncVisitDTO_newRecord_success() { +// // Arrange +// HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); +// when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) +// .thenReturn(null); +// when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncVisit())); +// when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); +// +// // Act +// String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); +// +// // Assert +// assertEquals("no of hbnc details saved: 1", result); +// verify(hbncVisitRepo).findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); +// verify(hbncVisitRepo).saveAll(anyList()); +// } +// +// @Test +// void testSaveHBNCDetails_hbncVisitDTO_existingRecord_success() { +// // Arrange +// HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); +// HbncVisit existingVisit = new HbncVisit(); +// existingVisit.setId(5L); +// +// when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) +// .thenReturn(existingVisit); +// when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); +// when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); +// +// // Act +// String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); +// +// // Assert +// assertEquals("no of hbnc details saved: 1", result); +// verify(hbncVisitRepo).findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); +// verify(hbncVisitRepo).saveAll(anyList()); +// } +// +// @Test +// void testSaveHBNCDetails_hbncVisitCardDTO_newRecord_success() { +// // Arrange +// HbncRequestDTO requestDTO = createHbncRequestDTOWithVisitCard(); +// when(hbncVisitCardRepo.findHbncVisitCardByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) +// .thenReturn(null); +// when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncVisitCard())); +// when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); +// +// // Act +// String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); +// +// // Assert +// assertEquals("no of hbnc details saved: 1", result); +// verify(hbncVisitCardRepo).findHbncVisitCardByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); +// verify(hbncVisitCardRepo).saveAll(anyList()); +// } +// +// @Test +// void testSaveHBNCDetails_hbncPart1DTO_newRecord_success() { +// // Arrange +// HbncRequestDTO requestDTO = createHbncRequestDTOWithPart1(); +// when(hbncPart1Repo.findHbncPart1ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) +// .thenReturn(null); +// when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncPart1())); +// when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList()); +// +// // Act +// String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); +// +// // Assert +// assertEquals("no of hbnc details saved: 1", result); +// verify(hbncPart1Repo).findHbncPart1ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); +// verify(hbncPart1Repo).saveAll(anyList()); +// } +// +// @Test +// void testSaveHBNCDetails_hbncPart2DTO_newRecord_success() { +// // Arrange +// HbncRequestDTO requestDTO = createHbncRequestDTOWithPart2(); +// when(hbncPart2repo.findHbncPart2ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) +// .thenReturn(null); +// when(hbncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncVisitCardRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncPart1Repo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(hbncPart2repo.saveAll(anyList())).thenReturn(Arrays.asList(new HbncPart2())); +// +// // Act +// String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); +// +// // Assert +// assertEquals("no of hbnc details saved: 1", result); +// verify(hbncPart2repo).findHbncPart2ByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate()); +// verify(hbncPart2repo).saveAll(anyList()); +// } +// +// @Test +// void testSaveHBNCDetails_exception() { +// // Arrange +// HbncRequestDTO requestDTO = createHbncRequestDTOWithVisit(); +// when(hbncVisitRepo.findHbncVisitByBenIdAndVisitNo(requestDTO.getBenId(), requestDTO.getHomeVisitDate())) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = service.saveHBNCDetails(Arrays.asList(requestDTO)); +// +// // Assert +// assertNull(result); +// } +// +// // getChildVaccinationDetails tests +// @Test +// void testGetChildVaccinationDetails_success() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// String userName = "testUser"; +// ChildVaccination vaccination = new ChildVaccination(); +// vaccination.setId(1L); +// vaccination.setBeneficiaryRegId(100L); +// vaccination.setVaccineName("BCG"); +// +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); +// when(childVaccinationRepo.getChildVaccinationDetails(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(vaccination)); +// when(beneficiaryRepo.getBenIdFromRegID(vaccination.getBeneficiaryRegId())) +// .thenReturn(BigInteger.valueOf(123L)); +// +// // Act +// List result = service.getChildVaccinationDetails(dto); +// +// // Assert +// assertNotNull(result); +// assertEquals(1, result.size()); +// assertEquals(123L, result.get(0).getBeneficiaryId()); +// verify(beneficiaryRepo).getUserName(dto.getAshaId()); +// verify(childVaccinationRepo).getChildVaccinationDetails(userName, dto.getFromDate(), dto.getToDate()); +// verify(beneficiaryRepo).getBenIdFromRegID(vaccination.getBeneficiaryRegId()); +// } +// +// @Test +// void testGetChildVaccinationDetails_exception() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = service.getChildVaccinationDetails(dto); +// +// // Assert +// assertNull(result); +// } +// +// // saveChildVaccinationDetails tests +// @Test +// void testSaveChildVaccinationDetails_newRecord_success() { +// // Arrange +// ChildVaccinationDTO dto = createChildVaccinationDTO(); +// Long benRegId = 100L; +// ChildVaccination savedVaccination = new ChildVaccination(); +// savedVaccination.setId(1L); +// savedVaccination.setBeneficiaryRegId(benRegId); +// savedVaccination.setVaccineId(dto.getVaccineId()); +// savedVaccination.setCreatedBy(dto.getCreatedBy()); +// savedVaccination.setCreatedDate(dto.getCreatedDate()); +// +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); +// when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( +// benRegId, dto.getCreatedDate(), dto.getVaccineName())) +// .thenReturn(null); +// when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); +// // Mocks for checkAndAddIncentives method +// when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(dto.getBeneficiaryId())); +// when(userRepo.getUserIdByName(dto.getCreatedBy())).thenReturn(1); +// when(vaccineRepo.getImmunizationServiceIdByVaccineId(dto.getVaccineId().shortValue())).thenReturn(1); +// // Additional mocks for incentive logic (immunizationServiceId < 6) +// IncentiveActivity incentiveActivity = new IncentiveActivity(); +// incentiveActivity.setId(1L); +// incentiveActivity.setName("IMMUNIZATION_0_1"); +// incentiveActivity.setRate(100); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")).thenReturn(incentiveActivity); +// when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); +// when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()))).thenReturn(null); +// when(recordRepo.save(any(IncentiveActivityRecord.class))).thenReturn(new IncentiveActivityRecord()); +// +// // Act +// String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); +// +// // Assert +// assertEquals("No of child vaccination details saved: 1", result); +// verify(beneficiaryRepo).getRegIDFromBenId(dto.getBeneficiaryId()); +// verify(childVaccinationRepo).findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( +// benRegId, dto.getCreatedDate(), dto.getVaccineName()); +// verify(childVaccinationRepo).saveAll(anyList()); +// } +// +// @Test +// void testSaveChildVaccinationDetails_existingRecord_success() { +// // Arrange +// ChildVaccinationDTO dto = createChildVaccinationDTO(); +// Long benRegId = 100L; +// ChildVaccination existingVaccination = new ChildVaccination(); +// existingVaccination.setId(5L); +// existingVaccination.setBeneficiaryRegId(benRegId); +// existingVaccination.setVaccineId(dto.getVaccineId()); +// existingVaccination.setCreatedBy(dto.getCreatedBy()); +// existingVaccination.setCreatedDate(dto.getCreatedDate()); +// +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); +// when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( +// benRegId, dto.getCreatedDate(), dto.getVaccineName())) +// .thenReturn(existingVaccination); +// when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVaccination)); +// // Mocks for checkAndAddIncentives method +// when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(dto.getBeneficiaryId())); +// when(userRepo.getUserIdByName(dto.getCreatedBy())).thenReturn(1); +// when(vaccineRepo.getImmunizationServiceIdByVaccineId(dto.getVaccineId().shortValue())).thenReturn(1); +// // Additional mocks for incentive logic (immunizationServiceId < 6) +// IncentiveActivity incentiveActivity = new IncentiveActivity(); +// incentiveActivity.setId(1L); +// incentiveActivity.setName("IMMUNIZATION_0_1"); +// incentiveActivity.setRate(100); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")).thenReturn(incentiveActivity); +// when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); +// when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(eq(1L), any(Timestamp.class), eq(dto.getBeneficiaryId()))).thenReturn(null); +// when(recordRepo.save(any(IncentiveActivityRecord.class))).thenReturn(new IncentiveActivityRecord()); +// +// // Act +// String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); +// +// // Assert +// assertEquals("No of child vaccination details saved: 1", result); +// verify(beneficiaryRepo).getRegIDFromBenId(dto.getBeneficiaryId()); +// verify(childVaccinationRepo).findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( +// benRegId, dto.getCreatedDate(), dto.getVaccineName()); +// verify(childVaccinationRepo).saveAll(anyList()); +// } +// +// @Test +// void testSaveChildVaccinationDetails_withIncentives_firstYear_success() { +// // Arrange +// ChildVaccinationDTO dto = createChildVaccinationDTO(); +// dto.setVaccineId(1); // First year vaccine +// Long benRegId = 100L; +// ChildVaccination savedVaccination = new ChildVaccination(); +// savedVaccination.setId(1L); +// savedVaccination.setBeneficiaryRegId(benRegId); +// savedVaccination.setVaccineId(1); +// savedVaccination.setCreatedDate(currentTime); +// savedVaccination.setCreatedBy("testUser"); +// +// IncentiveActivity incentiveActivity = new IncentiveActivity(); +// incentiveActivity.setId(1L); +// incentiveActivity.setRate(100); +// +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); +// when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( +// benRegId, dto.getCreatedDate(), dto.getVaccineName())) +// .thenReturn(null); +// when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); +// when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); +// when(userRepo.getUserIdByName("testUser")).thenReturn(1); +// when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 1)).thenReturn(1); // First year vaccine +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_0_1", "IMMUNIZATION")) +// .thenReturn(incentiveActivity); +// when(childVaccinationRepo.getFirstYearVaccineCountForBenId(benRegId)).thenReturn(5); +// when(childVaccinationRepo.getFirstYearVaccineCount()).thenReturn(5); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, 123L)) +// .thenReturn(null); +// +// // Act +// String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); +// +// // Assert +// assertEquals("No of child vaccination details saved: 1", result); +// verify(recordRepo).save(any(IncentiveActivityRecord.class)); +// } +// +// @Test +// void testSaveChildVaccinationDetails_withIncentives_secondYear_success() { +// // Arrange +// ChildVaccinationDTO dto = createChildVaccinationDTO(); +// dto.setVaccineId(7); // Second year vaccine +// Long benRegId = 100L; +// ChildVaccination savedVaccination = new ChildVaccination(); +// savedVaccination.setId(1L); +// savedVaccination.setBeneficiaryRegId(benRegId); +// savedVaccination.setVaccineId(7); +// savedVaccination.setCreatedDate(currentTime); +// savedVaccination.setCreatedBy("testUser"); +// +// IncentiveActivity incentiveActivity = new IncentiveActivity(); +// incentiveActivity.setId(2L); +// incentiveActivity.setRate(150); +// +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); +// when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( +// benRegId, dto.getCreatedDate(), dto.getVaccineName())) +// .thenReturn(null); +// when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); +// when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); +// when(userRepo.getUserIdByName("testUser")).thenReturn(1); +// when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 7)).thenReturn(7); // Second year vaccine +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_1_2", "IMMUNIZATION")) +// .thenReturn(incentiveActivity); +// when(childVaccinationRepo.getSecondYearVaccineCountForBenId(benRegId)).thenReturn(3); +// when(childVaccinationRepo.getSecondYearVaccineCount()).thenReturn(3); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, 123L)) +// .thenReturn(null); +// +// // Act +// String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); +// +// // Assert +// assertEquals("No of child vaccination details saved: 1", result); +// verify(recordRepo).save(any(IncentiveActivityRecord.class)); +// } +// +// @Test +// void testSaveChildVaccinationDetails_withIncentives_fifthYear_success() { +// // Arrange +// ChildVaccinationDTO dto = createChildVaccinationDTO(); +// dto.setVaccineId(8); // Fifth year vaccine +// Long benRegId = 100L; +// ChildVaccination savedVaccination = new ChildVaccination(); +// savedVaccination.setId(1L); +// savedVaccination.setBeneficiaryRegId(benRegId); +// savedVaccination.setVaccineId(8); +// savedVaccination.setCreatedDate(currentTime); +// savedVaccination.setCreatedBy("testUser"); +// +// IncentiveActivity incentiveActivity = new IncentiveActivity(); +// incentiveActivity.setId(3L); +// incentiveActivity.setRate(200); +// +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())).thenReturn(benRegId); +// when(childVaccinationRepo.findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName( +// benRegId, dto.getCreatedDate(), dto.getVaccineName())) +// .thenReturn(null); +// when(childVaccinationRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedVaccination)); +// when(beneficiaryRepo.getBenIdFromRegID(benRegId)).thenReturn(BigInteger.valueOf(123L)); +// when(userRepo.getUserIdByName("testUser")).thenReturn(1); +// when(vaccineRepo.getImmunizationServiceIdByVaccineId((short) 8)).thenReturn(8); // Fifth year vaccine +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("IMMUNIZATION_5", "IMMUNIZATION")) +// .thenReturn(incentiveActivity); +// when(childVaccinationRepo.checkDptVaccinatedUser(benRegId)).thenReturn(1); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(3L, currentTime, 123L)) +// .thenReturn(null); +// +// // Act +// String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); +// +// // Assert +// assertEquals("No of child vaccination details saved: 1", result); +// verify(recordRepo).save(any(IncentiveActivityRecord.class)); +// } +// +// @Test +// void testSaveChildVaccinationDetails_exception() { +// // Arrange +// ChildVaccinationDTO dto = createChildVaccinationDTO(); +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBeneficiaryId())) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = service.saveChildVaccinationDetails(Arrays.asList(dto)); +// +// // Assert +// assertNull(result); +// } +// +// // getAllChildVaccines tests +// @Test +// void testGetAllChildVaccines_success() { +// // Arrange +// String category = "CHILD"; +// Vaccine vaccine1 = createVaccine("Birth Dose Vaccines"); +// Vaccine vaccine2 = createVaccine("6 Weeks Vaccines"); +// Vaccine vaccine3 = createVaccine("10 Weeks Vaccines"); +// Vaccine vaccine4 = createVaccine("14 Weeks Vaccines"); +// Vaccine vaccine5 = createVaccine("9-12 Months"); +// Vaccine vaccine6 = createVaccine("16-24 Months Vaccines"); +// Vaccine vaccine7 = createVaccine("5-6 Years Vaccine"); +// Vaccine vaccine8 = createVaccine("10 Years Vaccine"); +// Vaccine vaccine9 = createVaccine("16 Years Vaccine"); +// Vaccine vaccine10 = createVaccine("Unknown Category"); +// +// when(vaccineRepo.getAllByCategory(category)).thenReturn(Arrays.asList( +// vaccine1, vaccine2, vaccine3, vaccine4, vaccine5, +// vaccine6, vaccine7, vaccine8, vaccine9, vaccine10 +// )); +// +// // Act +// List result = service.getAllChildVaccines(category); +// +// // Assert +// assertNotNull(result); +// assertEquals(10, result.size()); +// +// // Verify immunization service mappings +// assertEquals("BIRTH", result.get(0).getImmunizationService()); +// assertEquals("WEEK_6", result.get(1).getImmunizationService()); +// assertEquals("WEEK_10", result.get(2).getImmunizationService()); +// assertEquals("WEEK_14", result.get(3).getImmunizationService()); +// assertEquals("MONTH_9_12", result.get(4).getImmunizationService()); +// assertEquals("MONTH_16_24", result.get(5).getImmunizationService()); +// assertEquals("YEAR_5_6", result.get(6).getImmunizationService()); +// assertEquals("YEAR_10", result.get(7).getImmunizationService()); +// assertEquals("YEAR_16", result.get(8).getImmunizationService()); +// assertEquals("CATCH_UP", result.get(9).getImmunizationService()); +// +// verify(vaccineRepo).getAllByCategory(category); +// } +// +// @Test +// void testGetAllChildVaccines_exception() { +// // Arrange +// String category = "CHILD"; +// when(vaccineRepo.getAllByCategory(category)).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = service.getAllChildVaccines(category); +// +// // Assert +// assertNull(result); +// } +// +// // Helper methods to create test data +// private HbycDTO createHbycDTO() { +// HbycDTO dto = new HbycDTO(); +// dto.setBenId(123L); +// dto.setCreatedDate(currentTime); +// dto.setCreatedBy("testUser"); +// dto.setUpdatedDate(currentTime); +// dto.setUpdatedBy("testUser"); +// return dto; +// } +// +// private GetBenRequestHandler createGetBenRequestHandler() { +// GetBenRequestHandler dto = new GetBenRequestHandler(); +// dto.setAshaId(1); +// dto.setFromDate(currentTime); +// dto.setToDate(currentTime); +// return dto; +// } +// +// private HbncRequestDTO createHbncRequestDTOWithVisit() { +// HbncRequestDTO dto = new HbncRequestDTO(); +// dto.setId(1L); +// dto.setBenId(123L); +// dto.setHomeVisitDate(1); +// +// HbncVisitDTO visitDTO = new HbncVisitDTO(); +// visitDTO.setBenId(123L); +// visitDTO.setVisitNo(1); +// dto.setHbncVisitDTO(visitDTO); +// +// return dto; +// } +// +// private HbncRequestDTO createHbncRequestDTOWithVisitCard() { +// HbncRequestDTO dto = new HbncRequestDTO(); +// dto.setId(2L); +// dto.setBenId(124L); +// dto.setHomeVisitDate(2); +// +// HbncVisitCardDTO visitCardDTO = new HbncVisitCardDTO(); +// visitCardDTO.setBenId(124L); +// visitCardDTO.setVisitNo(2); +// dto.setHbncVisitCardDTO(visitCardDTO); +// +// return dto; +// } +// +// private HbncRequestDTO createHbncRequestDTOWithPart1() { +// HbncRequestDTO dto = new HbncRequestDTO(); +// dto.setId(3L); +// dto.setBenId(125L); +// dto.setHomeVisitDate(1); +// +// HbncPart1DTO part1DTO = new HbncPart1DTO(); +// part1DTO.setBenId(125L); +// part1DTO.setVisitNo(1); +// dto.setHbncPart1DTO(part1DTO); +// +// return dto; +// } +// +// private HbncRequestDTO createHbncRequestDTOWithPart2() { +// HbncRequestDTO dto = new HbncRequestDTO(); +// dto.setId(4L); +// dto.setBenId(126L); +// dto.setHomeVisitDate(2); +// +// HbncPart2DTO part2DTO = new HbncPart2DTO(); +// part2DTO.setBenId(126L); +// part2DTO.setVisitNo(2); +// dto.setHbncPart2DTO(part2DTO); +// +// return dto; +// } +// +// private ChildVaccinationDTO createChildVaccinationDTO() { +// ChildVaccinationDTO dto = new ChildVaccinationDTO(); +// dto.setBeneficiaryId(123L); +// dto.setVaccineName("BCG"); +// dto.setVaccineId(1); +// dto.setCreatedDate(currentTime); +// dto.setCreatedBy("testUser"); +// dto.setLastModDate(currentTime); +// dto.setModifiedBy("testUser"); +// return dto; +// } +// +// private Vaccine createVaccine(String immunizationService) { +// Vaccine vaccine = new Vaccine(); +// vaccine.setVaccineId((short) 1); +// vaccine.setVaccineName("Test Vaccine"); +// vaccine.setImmunizationService(immunizationService); +// return vaccine; +// } +//} diff --git a/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java index b02330e46..c7133a969 100644 --- a/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/CoupleServiceImplTest.java @@ -1,685 +1,685 @@ -package com.iemr.flw.service.impl; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import com.iemr.flw.domain.iemr.*; -import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.EligibleCoupleDTO; -import com.iemr.flw.dto.iemr.EligibleCoupleTrackingDTO; -import com.iemr.flw.repo.identity.BeneficiaryRepo; -import com.iemr.flw.repo.iemr.*; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.modelmapper.ModelMapper; - -import java.lang.reflect.Field; -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class CoupleServiceImplTest { - @Mock - private EligibleCoupleRegisterRepo eligibleCoupleRegisterRepo; - @Mock - private EligibleCoupleTrackingRepo eligibleCoupleTrackingRepo; - @Mock - private IncentivesRepo incentivesRepo; - @Mock - private UserServiceRoleRepo userRepo; - @Mock - private IncentiveRecordRepo recordRepo; - @Mock - private BeneficiaryRepo beneficiaryRepo; - @Mock - private ObjectMapper mapper; - @Mock - private ModelMapper modelMapper; - @InjectMocks - private CoupleServiceImpl coupleService; - - @BeforeEach - void setUp() throws Exception { - // Set up ObjectMapper and ModelMapper fields using reflection - Field mapperField = CoupleServiceImpl.class.getDeclaredField("mapper"); - mapperField.setAccessible(true); - mapperField.set(coupleService, mapper); - - Field modelMapperField = CoupleServiceImpl.class.getDeclaredField("modelMapper"); - modelMapperField.setAccessible(true); - modelMapperField.set(coupleService, modelMapper); - } - - @Test - void registerEligibleCouple_existingECRWithIncentives_success() { - // Arrange - EligibleCoupleDTO dto = new EligibleCoupleDTO(); - dto.setBenId(1L); - dto.setNumLiveChildren(1); - dto.setMarriageFirstChildGap(3); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); - existingECR.setId(1L); - existingECR.setNumLiveChildren(0); - - IncentiveActivity activity = new IncentiveActivity(); - activity.setId(1L); - activity.getName(); - activity.setRate(100); - - when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) - .thenReturn(activity); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) - .thenReturn(null); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - - // Act - String result = coupleService.registerEligibleCouple(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ecr details saved: 1", result); - verify(eligibleCoupleRegisterRepo).findEligibleCoupleRegisterByBenId(1L); - verify(incentivesRepo).findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING"); - verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); - verify(userRepo).getUserIdByName("testUser"); - verify(eligibleCoupleRegisterRepo).saveAll(anyList()); - verify(recordRepo).saveAll(anyList()); - verify(modelMapper).map(dto, existingECR); - } - - @Test - void registerEligibleCouple_secondChildGapIncentive_success() { - // Arrange - EligibleCoupleDTO dto = new EligibleCoupleDTO(); - dto.setBenId(1L); - dto.setNumLiveChildren(2); - dto.setMarriageFirstChildGap(2); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); - existingECR.setId(1L); - existingECR.setNumLiveChildren(1); - - IncentiveActivity activity = new IncentiveActivity(); - activity.setId(2L); - activity.setName("Second child gap"); - activity.setRate(200); - - when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", "FAMILY PLANNING")) - .thenReturn(activity); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) - .thenReturn(null); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - - // Act - String result = coupleService.registerEligibleCouple(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ecr details saved: 1", result); - verify(incentivesRepo).findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", "FAMILY PLANNING"); - } - - @Test - void registerEligibleCouple_newECR_success() { - // Arrange - EligibleCoupleDTO dto = new EligibleCoupleDTO(); - dto.setBenId(1L); - dto.setNumLiveChildren(0); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - EligibleCoupleRegister newECR = new EligibleCoupleRegister(); - newECR.setId(null); - - when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(null); - when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(newECR)); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - doAnswer(invocation -> { - EligibleCoupleDTO source = invocation.getArgument(0); - EligibleCoupleRegister target = invocation.getArgument(1); - target.setCreatedBy(source.getCreatedBy()); - return null; - }).when(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); - - // Act - String result = coupleService.registerEligibleCouple(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ecr details saved: 1", result); - verify(eligibleCoupleRegisterRepo).findEligibleCoupleRegisterByBenId(1L); - verify(eligibleCoupleRegisterRepo).saveAll(anyList()); - verify(recordRepo).saveAll(anyList()); - verify(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); - } - - @Test - void registerEligibleCouple_existingRecord_noIncentive() { - // Arrange - EligibleCoupleDTO dto = new EligibleCoupleDTO(); - dto.setBenId(1L); - dto.setNumLiveChildren(1); - dto.setMarriageFirstChildGap(3); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); - existingECR.setId(1L); - existingECR.setNumLiveChildren(0); - - IncentiveActivity activity = new IncentiveActivity(); - activity.setId(1L); - activity.setName("Marriage gap"); - activity.setRate(100); - - IncentiveActivityRecord existingRecord = new IncentiveActivityRecord(); - - when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) - .thenReturn(activity); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) - .thenReturn(existingRecord); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - - // Act - String result = coupleService.registerEligibleCouple(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ecr details saved: 1", result); - verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); - // getUserIdByName should still be called even for existing record due to service logic - verify(userRepo).getUserIdByName("testUser"); - } - - @Test - void registerEligibleCouple_exception_returnsError() { - // Arrange - EligibleCoupleDTO dto = new EligibleCoupleDTO(); - dto.setBenId(1L); - List dtoList = Arrays.asList(dto); - - when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = coupleService.registerEligibleCouple(dtoList); - - // Assert - assertNotNull(result); - assertTrue(result.startsWith("error while saving ecr details: ")); - assertTrue(result.contains("Database error")); - } - - @Test - void registerEligibleCoupleTracking_newECTWithAntaraIncentive_success() { - // Arrange - EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); - dto.setBenId(1L); - dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setMethodOfContraception("ANTRA Injection"); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - EligibleCoupleTracking newECT = new EligibleCoupleTracking(); - - IncentiveActivity antaraActivity = new IncentiveActivity(); - antaraActivity.setId(1L); - antaraActivity.setName("ANTARA_PROG_1"); - antaraActivity.setRate(500); - - when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) - .thenReturn(null); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING")) - .thenReturn(antaraActivity); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) - .thenReturn(null); - when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(Arrays.asList(newECT)); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - doAnswer(invocation -> { - EligibleCoupleTrackingDTO source = invocation.getArgument(0); - EligibleCoupleTracking target = invocation.getArgument(1); - target.setCreatedBy(source.getCreatedBy()); - target.setMethodOfContraception(source.getMethodOfContraception()); - target.setBenId(source.getBenId()); - target.setCreatedDate(source.getCreatedDate()); - return null; - }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); - - // Act - String result = coupleService.registerEligibleCoupleTracking(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ect details saved: 1", result); - verify(eligibleCoupleTrackingRepo).findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate()); - verify(userRepo).getUserIdByName("testUser"); - verify(eligibleCoupleTrackingRepo).findCouplesHadAntara(1L); - verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING"); - verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); - verify(eligibleCoupleTrackingRepo).saveAll(anyList()); - verify(recordRepo).saveAll(anyList()); - } - - @Test - void registerEligibleCoupleTracking_existingECTWithAntaraProg2_success() { - // Arrange - EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); - dto.setBenId(1L); - dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setMethodOfContraception("ANTRA Injection"); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - EligibleCoupleTracking existingECT = new EligibleCoupleTracking(); - existingECT.setId(1L); - - List antaraHistory = Arrays.asList(new EligibleCoupleTracking()); - - IncentiveActivity antaraActivity2 = new IncentiveActivity(); - antaraActivity2.setId(2L); - antaraActivity2.setName("ANTARA_PROG_2"); - antaraActivity2.setRate(600); - - when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) - .thenReturn(existingECT); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(antaraHistory); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_2", "FAMILY PLANNING")) - .thenReturn(antaraActivity2); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) - .thenReturn(null); - when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECT)); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - doAnswer(invocation -> { - EligibleCoupleTrackingDTO source = invocation.getArgument(0); - EligibleCoupleTracking target = invocation.getArgument(1); - target.setCreatedBy(source.getCreatedBy()); - target.setMethodOfContraception(source.getMethodOfContraception()); - target.setBenId(source.getBenId()); - target.setCreatedDate(source.getCreatedDate()); - return null; - }).when(modelMapper).map(dto, existingECT); - - // Act - String result = coupleService.registerEligibleCoupleTracking(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ect details saved: 1", result); - verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_2", "FAMILY PLANNING"); - verify(modelMapper).map(dto, existingECT); - } - - @Test - void registerEligibleCoupleTracking_antaraProg3And4_success() { - // Test for ANTARA_PROG_3 (numAntaraDosage = 2) - EligibleCoupleTrackingDTO dto1 = new EligibleCoupleTrackingDTO(); - dto1.setBenId(1L); - dto1.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); - dto1.setMethodOfContraception("ANTRA Injection"); - dto1.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto1.setCreatedBy("testUser"); - - List antaraHistory3 = Arrays.asList( - new EligibleCoupleTracking(), new EligibleCoupleTracking() - ); - - IncentiveActivity antaraActivity3 = new IncentiveActivity(); - antaraActivity3.setId(3L); - antaraActivity3.setName("ANTARA_PROG_3"); - antaraActivity3.setRate(700); - - when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto1.getVisitDate())) - .thenReturn(null); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(antaraHistory3); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_3", "FAMILY PLANNING")) - .thenReturn(antaraActivity3); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) - .thenReturn(null); - when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - doAnswer(invocation -> { - EligibleCoupleTrackingDTO source = invocation.getArgument(0); - EligibleCoupleTracking target = invocation.getArgument(1); - target.setCreatedBy(source.getCreatedBy()); - target.setMethodOfContraception(source.getMethodOfContraception()); - target.setBenId(source.getBenId()); - target.setCreatedDate(source.getCreatedDate()); - return null; - }).when(modelMapper).map(eq(dto1), any(EligibleCoupleTracking.class)); - - String result1 = coupleService.registerEligibleCoupleTracking(Arrays.asList(dto1)); - assertNotNull(result1); - verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_3", "FAMILY PLANNING"); - - // Test for ANTARA_PROG_4 (numAntaraDosage = 3) - reset(eligibleCoupleTrackingRepo); - reset(incentivesRepo); - reset(recordRepo); - reset(userRepo); - - EligibleCoupleTrackingDTO dto2 = new EligibleCoupleTrackingDTO(); - dto2.setBenId(2L); - dto2.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); - dto2.setMethodOfContraception("ANTRA Injection"); - dto2.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto2.setCreatedBy("testUser"); - - List antaraHistory4 = Arrays.asList( - new EligibleCoupleTracking(), new EligibleCoupleTracking(), new EligibleCoupleTracking() - ); - - IncentiveActivity antaraActivity4 = new IncentiveActivity(); - antaraActivity4.setId(4L); - antaraActivity4.setName("ANTARA_PROG_4"); - antaraActivity4.setRate(800); - - when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(2L, dto2.getVisitDate())) - .thenReturn(null); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleTrackingRepo.findCouplesHadAntara(2L)).thenReturn(antaraHistory4); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_4", "FAMILY PLANNING")) - .thenReturn(antaraActivity4); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) - .thenReturn(null); - when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - doAnswer(invocation -> { - EligibleCoupleTrackingDTO source = invocation.getArgument(0); - EligibleCoupleTracking target = invocation.getArgument(1); - target.setCreatedBy(source.getCreatedBy()); - target.setMethodOfContraception(source.getMethodOfContraception()); - target.setBenId(source.getBenId()); - target.setCreatedDate(source.getCreatedDate()); - return null; - }).when(modelMapper).map(eq(dto2), any(EligibleCoupleTracking.class)); - - String result2 = coupleService.registerEligibleCoupleTracking(Arrays.asList(dto2)); - assertNotNull(result2); - verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_4", "FAMILY PLANNING"); - } - - @Test - void registerEligibleCoupleTracking_noIncentiveForNonAntara_success() { - // Arrange - EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); - dto.setBenId(1L); - dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setMethodOfContraception("Other method"); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) - .thenReturn(null); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); - when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - doAnswer(invocation -> { - EligibleCoupleTrackingDTO source = invocation.getArgument(0); - EligibleCoupleTracking target = invocation.getArgument(1); - target.setCreatedBy(source.getCreatedBy()); - target.setMethodOfContraception(source.getMethodOfContraception()); - target.setBenId(source.getBenId()); - target.setCreatedDate(source.getCreatedDate()); - return null; - }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); - - // Act - String result = coupleService.registerEligibleCoupleTracking(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ect details saved: 1", result); - verify(incentivesRepo, never()).findIncentiveMasterByNameAndGroup(anyString(), anyString()); - } - - @Test - void registerEligibleCoupleTracking_exception_returnsError() { - // Arrange - EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); - dto.setBenId(1L); - List dtoList = Arrays.asList(dto); - - when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(anyLong(), any())) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = coupleService.registerEligibleCoupleTracking(dtoList); - - // Assert - assertNotNull(result); - assertTrue(result.startsWith("error while saving ect details: ")); - assertTrue(result.contains("Database error")); - } - - @Test - void getEligibleCoupleRegRecords_success() { - // Arrange - GetBenRequestHandler dto = mock(GetBenRequestHandler.class); - Integer ashaId = 123; - Timestamp fromDate = Timestamp.valueOf(LocalDateTime.now().minusDays(30)); - Timestamp toDate = Timestamp.valueOf(LocalDateTime.now()); - - when(dto.getAshaId()).thenReturn(ashaId); - when(dto.getFromDate()).thenReturn(fromDate); - when(dto.getToDate()).thenReturn(toDate); - - String userName = "testUser"; - List registerList = Arrays.asList(new EligibleCoupleRegister()); - EligibleCoupleDTO mappedDTO = new EligibleCoupleDTO(); - - when(beneficiaryRepo.getUserName(ashaId)).thenReturn(userName); - when(eligibleCoupleRegisterRepo.getECRegRecords(userName, fromDate, toDate)).thenReturn(registerList); - when(mapper.convertValue(any(EligibleCoupleRegister.class), eq(EligibleCoupleDTO.class))) - .thenReturn(mappedDTO); - - // Act - String result = coupleService.getEligibleCoupleRegRecords(dto); - - // Assert - assertNotNull(result); - @SuppressWarnings("unchecked") - List resultList = new Gson().fromJson(result, List.class); - assertEquals(1, resultList.size()); - - verify(beneficiaryRepo).getUserName(ashaId); - verify(eligibleCoupleRegisterRepo).getECRegRecords(userName, fromDate, toDate); - verify(mapper).convertValue(any(EligibleCoupleRegister.class), eq(EligibleCoupleDTO.class)); - } - - @Test - void getEligibleCoupleRegRecords_exception_returnsNull() { - // Arrange - GetBenRequestHandler dto = mock(GetBenRequestHandler.class); - when(dto.getAshaId()).thenReturn(123); - when(beneficiaryRepo.getUserName(123)).thenThrow(new RuntimeException("Database error")); - - // Act - String result = coupleService.getEligibleCoupleRegRecords(dto); - - // Assert - assertNull(result); - verify(beneficiaryRepo).getUserName(123); - } - - @Test - void getEligibleCoupleTracking_success() { - // Arrange - GetBenRequestHandler dto = mock(GetBenRequestHandler.class); - Integer ashaId = 123; - Timestamp fromDate = Timestamp.valueOf(LocalDateTime.now().minusDays(30)); - Timestamp toDate = Timestamp.valueOf(LocalDateTime.now()); - - when(dto.getAshaId()).thenReturn(ashaId); - when(dto.getFromDate()).thenReturn(fromDate); - when(dto.getToDate()).thenReturn(toDate); - - String userName = "testUser"; - List trackingList = Arrays.asList(new EligibleCoupleTracking()); - EligibleCoupleTrackingDTO mappedDTO = new EligibleCoupleTrackingDTO(); - - when(beneficiaryRepo.getUserName(ashaId)).thenReturn(userName); - when(eligibleCoupleTrackingRepo.getECTrackRecords(userName, fromDate, toDate)).thenReturn(trackingList); - when(mapper.convertValue(any(EligibleCoupleTracking.class), eq(EligibleCoupleTrackingDTO.class))) - .thenReturn(mappedDTO); - - // Act - List result = coupleService.getEligibleCoupleTracking(dto); - - // Assert - assertNotNull(result); - assertEquals(1, result.size()); - assertEquals(mappedDTO, result.get(0)); - - verify(beneficiaryRepo).getUserName(ashaId); - verify(eligibleCoupleTrackingRepo).getECTrackRecords(userName, fromDate, toDate); - verify(mapper).convertValue(any(EligibleCoupleTracking.class), eq(EligibleCoupleTrackingDTO.class)); - } - - @Test - void getEligibleCoupleTracking_exception_returnsNull() { - // Arrange - GetBenRequestHandler dto = mock(GetBenRequestHandler.class); - when(dto.getAshaId()).thenReturn(123); - when(beneficiaryRepo.getUserName(123)).thenThrow(new RuntimeException("Database error")); - - // Act - List result = coupleService.getEligibleCoupleTracking(dto); - - // Assert - assertNull(result); - verify(beneficiaryRepo).getUserName(123); - } - - @Test - void registerEligibleCoupleTracking_nullIncentiveActivity_noRecordAdded() { - // Arrange - EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); - dto.setBenId(1L); - dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setMethodOfContraception("ANTRA Injection"); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) - .thenReturn(null); - when(userRepo.getUserIdByName("testUser")).thenReturn(123); - when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING")) - .thenReturn(null); - when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - doAnswer(invocation -> { - EligibleCoupleTrackingDTO source = invocation.getArgument(0); - EligibleCoupleTracking target = invocation.getArgument(1); - target.setCreatedBy(source.getCreatedBy()); - target.setMethodOfContraception(source.getMethodOfContraception()); - target.setBenId(source.getBenId()); - target.setCreatedDate(source.getCreatedDate()); - return null; - }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); - - // Act - String result = coupleService.registerEligibleCoupleTracking(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ect details saved: 1", result); - verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING"); - verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); - } - - @Test - void registerEligibleCouple_nullIncentiveActivity_noRecordCreated() { - // Arrange - EligibleCoupleDTO dto = new EligibleCoupleDTO(); - dto.setBenId(1L); - dto.setNumLiveChildren(1); - dto.setMarriageFirstChildGap(3); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); - existingECR.setId(1L); - existingECR.setNumLiveChildren(0); - - when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) - .thenReturn(null); - when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - - // Act - String result = coupleService.registerEligibleCouple(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ecr details saved: 1", result); - verify(incentivesRepo).findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING"); - verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); - } - - @Test - void registerEligibleCouple_existingECRNullNumLiveChildren_newRecord() { - // Arrange - EligibleCoupleDTO dto = new EligibleCoupleDTO(); - dto.setBenId(1L); - dto.setNumLiveChildren(1); - dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); - dto.setCreatedBy("testUser"); - List dtoList = Arrays.asList(dto); - - EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); - existingECR.setId(1L); - existingECR.setNumLiveChildren(null); // null numLiveChildren should trigger new record creation - - when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); - when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); - when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); - - // Act - String result = coupleService.registerEligibleCouple(dtoList); - - // Assert - assertNotNull(result); - assertEquals("no of ecr details saved: 1", result); - // Should not call incentive methods because numLiveChildren is null - verify(incentivesRepo, never()).findIncentiveMasterByNameAndGroup(anyString(), anyString()); - verify(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); - } -} +//package com.iemr.flw.service.impl; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.google.gson.Gson; +//import com.iemr.flw.domain.iemr.*; +//import com.iemr.flw.dto.identity.GetBenRequestHandler; +//import com.iemr.flw.dto.iemr.EligibleCoupleDTO; +//import com.iemr.flw.dto.iemr.EligibleCoupleTrackingDTO; +//import com.iemr.flw.repo.identity.BeneficiaryRepo; +//import com.iemr.flw.repo.iemr.*; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +//import org.junit.jupiter.api.extension.ExtendWith; +//import org.mockito.InjectMocks; +//import org.mockito.Mock; +//import org.mockito.junit.jupiter.MockitoExtension; +//import org.modelmapper.ModelMapper; +// +//import java.lang.reflect.Field; +//import java.sql.Timestamp; +//import java.time.LocalDateTime; +//import java.util.*; +// +//import static org.junit.jupiter.api.Assertions.*; +//import static org.mockito.ArgumentMatchers.*; +//import static org.mockito.Mockito.*; +// +//@ExtendWith(MockitoExtension.class) +//class CoupleServiceImplTest { +// @Mock +// private EligibleCoupleRegisterRepo eligibleCoupleRegisterRepo; +// @Mock +// private EligibleCoupleTrackingRepo eligibleCoupleTrackingRepo; +// @Mock +// private IncentivesRepo incentivesRepo; +// @Mock +// private UserServiceRoleRepo userRepo; +// @Mock +// private IncentiveRecordRepo recordRepo; +// @Mock +// private BeneficiaryRepo beneficiaryRepo; +// @Mock +// private ObjectMapper mapper; +// @Mock +// private ModelMapper modelMapper; +// @InjectMocks +// private CoupleServiceImpl coupleService; +// +// @BeforeEach +// void setUp() throws Exception { +// // Set up ObjectMapper and ModelMapper fields using reflection +// Field mapperField = CoupleServiceImpl.class.getDeclaredField("mapper"); +// mapperField.setAccessible(true); +// mapperField.set(coupleService, mapper); +// +// Field modelMapperField = CoupleServiceImpl.class.getDeclaredField("modelMapper"); +// modelMapperField.setAccessible(true); +// modelMapperField.set(coupleService, modelMapper); +// } +// +// @Test +// void registerEligibleCouple_existingECRWithIncentives_success() { +// // Arrange +// EligibleCoupleDTO dto = new EligibleCoupleDTO(); +// dto.setBenId(1L); +// dto.setNumLiveChildren(1); +// dto.setMarriageFirstChildGap(3); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); +// existingECR.setId(1L); +// existingECR.setNumLiveChildren(0); +// +// IncentiveActivity activity = new IncentiveActivity(); +// activity.setId(1L); +// activity.getName(); +// activity.setRate(100); +// +// when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) +// .thenReturn(activity); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) +// .thenReturn(null); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// +// // Act +// String result = coupleService.registerEligibleCouple(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ecr details saved: 1", result); +// verify(eligibleCoupleRegisterRepo).findEligibleCoupleRegisterByBenId(1L); +// verify(incentivesRepo).findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING"); +// verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); +// verify(userRepo).getUserIdByName("testUser"); +// verify(eligibleCoupleRegisterRepo).saveAll(anyList()); +// verify(recordRepo).saveAll(anyList()); +// verify(modelMapper).map(dto, existingECR); +// } +// +// @Test +// void registerEligibleCouple_secondChildGapIncentive_success() { +// // Arrange +// EligibleCoupleDTO dto = new EligibleCoupleDTO(); +// dto.setBenId(1L); +// dto.setNumLiveChildren(2); +// dto.setMarriageFirstChildGap(2); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); +// existingECR.setId(1L); +// existingECR.setNumLiveChildren(1); +// +// IncentiveActivity activity = new IncentiveActivity(); +// activity.setId(2L); +// activity.setName("Second child gap"); +// activity.setRate(200); +// +// when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", "FAMILY PLANNING")) +// .thenReturn(activity); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) +// .thenReturn(null); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// +// // Act +// String result = coupleService.registerEligibleCouple(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ecr details saved: 1", result); +// verify(incentivesRepo).findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", "FAMILY PLANNING"); +// } +// +// @Test +// void registerEligibleCouple_newECR_success() { +// // Arrange +// EligibleCoupleDTO dto = new EligibleCoupleDTO(); +// dto.setBenId(1L); +// dto.setNumLiveChildren(0); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// EligibleCoupleRegister newECR = new EligibleCoupleRegister(); +// newECR.setId(null); +// +// when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(null); +// when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(newECR)); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// doAnswer(invocation -> { +// EligibleCoupleDTO source = invocation.getArgument(0); +// EligibleCoupleRegister target = invocation.getArgument(1); +// target.setCreatedBy(source.getCreatedBy()); +// return null; +// }).when(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); +// +// // Act +// String result = coupleService.registerEligibleCouple(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ecr details saved: 1", result); +// verify(eligibleCoupleRegisterRepo).findEligibleCoupleRegisterByBenId(1L); +// verify(eligibleCoupleRegisterRepo).saveAll(anyList()); +// verify(recordRepo).saveAll(anyList()); +// verify(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); +// } +// +// @Test +// void registerEligibleCouple_existingRecord_noIncentive() { +// // Arrange +// EligibleCoupleDTO dto = new EligibleCoupleDTO(); +// dto.setBenId(1L); +// dto.setNumLiveChildren(1); +// dto.setMarriageFirstChildGap(3); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); +// existingECR.setId(1L); +// existingECR.setNumLiveChildren(0); +// +// IncentiveActivity activity = new IncentiveActivity(); +// activity.setId(1L); +// activity.setName("Marriage gap"); +// activity.setRate(100); +// +// IncentiveActivityRecord existingRecord = new IncentiveActivityRecord(); +// +// when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) +// .thenReturn(activity); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) +// .thenReturn(existingRecord); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// +// // Act +// String result = coupleService.registerEligibleCouple(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ecr details saved: 1", result); +// verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); +// // getUserIdByName should still be called even for existing record due to service logic +// verify(userRepo).getUserIdByName("testUser"); +// } +// +// @Test +// void registerEligibleCouple_exception_returnsError() { +// // Arrange +// EligibleCoupleDTO dto = new EligibleCoupleDTO(); +// dto.setBenId(1L); +// List dtoList = Arrays.asList(dto); +// +// when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = coupleService.registerEligibleCouple(dtoList); +// +// // Assert +// assertNotNull(result); +// assertTrue(result.startsWith("error while saving ecr details: ")); +// assertTrue(result.contains("Database error")); +// } +// +// @Test +// void registerEligibleCoupleTracking_newECTWithAntaraIncentive_success() { +// // Arrange +// EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); +// dto.setBenId(1L); +// dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setMethodOfContraception("ANTRA Injection"); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// EligibleCoupleTracking newECT = new EligibleCoupleTracking(); +// +// IncentiveActivity antaraActivity = new IncentiveActivity(); +// antaraActivity.setId(1L); +// antaraActivity.setName("ANTARA_PROG_1"); +// antaraActivity.setRate(500); +// +// when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) +// .thenReturn(null); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING")) +// .thenReturn(antaraActivity); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) +// .thenReturn(null); +// when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(Arrays.asList(newECT)); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// doAnswer(invocation -> { +// EligibleCoupleTrackingDTO source = invocation.getArgument(0); +// EligibleCoupleTracking target = invocation.getArgument(1); +// target.setCreatedBy(source.getCreatedBy()); +// target.setMethodOfContraception(source.getMethodOfContraception()); +// target.setBenId(source.getBenId()); +// target.setCreatedDate(source.getCreatedDate()); +// return null; +// }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); +// +// // Act +// String result = coupleService.registerEligibleCoupleTracking(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ect details saved: 1", result); +// verify(eligibleCoupleTrackingRepo).findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate()); +// verify(userRepo).getUserIdByName("testUser"); +// verify(eligibleCoupleTrackingRepo).findCouplesHadAntara(1L); +// verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING"); +// verify(recordRepo).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); +// verify(eligibleCoupleTrackingRepo).saveAll(anyList()); +// verify(recordRepo).saveAll(anyList()); +// } +// +// @Test +// void registerEligibleCoupleTracking_existingECTWithAntaraProg2_success() { +// // Arrange +// EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); +// dto.setBenId(1L); +// dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setMethodOfContraception("ANTRA Injection"); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// EligibleCoupleTracking existingECT = new EligibleCoupleTracking(); +// existingECT.setId(1L); +// +// List antaraHistory = Arrays.asList(new EligibleCoupleTracking()); +// +// IncentiveActivity antaraActivity2 = new IncentiveActivity(); +// antaraActivity2.setId(2L); +// antaraActivity2.setName("ANTARA_PROG_2"); +// antaraActivity2.setRate(600); +// +// when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) +// .thenReturn(existingECT); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(antaraHistory); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_2", "FAMILY PLANNING")) +// .thenReturn(antaraActivity2); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) +// .thenReturn(null); +// when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECT)); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// doAnswer(invocation -> { +// EligibleCoupleTrackingDTO source = invocation.getArgument(0); +// EligibleCoupleTracking target = invocation.getArgument(1); +// target.setCreatedBy(source.getCreatedBy()); +// target.setMethodOfContraception(source.getMethodOfContraception()); +// target.setBenId(source.getBenId()); +// target.setCreatedDate(source.getCreatedDate()); +// return null; +// }).when(modelMapper).map(dto, existingECT); +// +// // Act +// String result = coupleService.registerEligibleCoupleTracking(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ect details saved: 1", result); +// verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_2", "FAMILY PLANNING"); +// verify(modelMapper).map(dto, existingECT); +// } +// +// @Test +// void registerEligibleCoupleTracking_antaraProg3And4_success() { +// // Test for ANTARA_PROG_3 (numAntaraDosage = 2) +// EligibleCoupleTrackingDTO dto1 = new EligibleCoupleTrackingDTO(); +// dto1.setBenId(1L); +// dto1.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); +// dto1.setMethodOfContraception("ANTRA Injection"); +// dto1.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto1.setCreatedBy("testUser"); +// +// List antaraHistory3 = Arrays.asList( +// new EligibleCoupleTracking(), new EligibleCoupleTracking() +// ); +// +// IncentiveActivity antaraActivity3 = new IncentiveActivity(); +// antaraActivity3.setId(3L); +// antaraActivity3.setName("ANTARA_PROG_3"); +// antaraActivity3.setRate(700); +// +// when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto1.getVisitDate())) +// .thenReturn(null); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(antaraHistory3); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_3", "FAMILY PLANNING")) +// .thenReturn(antaraActivity3); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) +// .thenReturn(null); +// when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// doAnswer(invocation -> { +// EligibleCoupleTrackingDTO source = invocation.getArgument(0); +// EligibleCoupleTracking target = invocation.getArgument(1); +// target.setCreatedBy(source.getCreatedBy()); +// target.setMethodOfContraception(source.getMethodOfContraception()); +// target.setBenId(source.getBenId()); +// target.setCreatedDate(source.getCreatedDate()); +// return null; +// }).when(modelMapper).map(eq(dto1), any(EligibleCoupleTracking.class)); +// +// String result1 = coupleService.registerEligibleCoupleTracking(Arrays.asList(dto1)); +// assertNotNull(result1); +// verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_3", "FAMILY PLANNING"); +// +// // Test for ANTARA_PROG_4 (numAntaraDosage = 3) +// reset(eligibleCoupleTrackingRepo); +// reset(incentivesRepo); +// reset(recordRepo); +// reset(userRepo); +// +// EligibleCoupleTrackingDTO dto2 = new EligibleCoupleTrackingDTO(); +// dto2.setBenId(2L); +// dto2.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); +// dto2.setMethodOfContraception("ANTRA Injection"); +// dto2.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto2.setCreatedBy("testUser"); +// +// List antaraHistory4 = Arrays.asList( +// new EligibleCoupleTracking(), new EligibleCoupleTracking(), new EligibleCoupleTracking() +// ); +// +// IncentiveActivity antaraActivity4 = new IncentiveActivity(); +// antaraActivity4.setId(4L); +// antaraActivity4.setName("ANTARA_PROG_4"); +// antaraActivity4.setRate(800); +// +// when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(2L, dto2.getVisitDate())) +// .thenReturn(null); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleTrackingRepo.findCouplesHadAntara(2L)).thenReturn(antaraHistory4); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_4", "FAMILY PLANNING")) +// .thenReturn(antaraActivity4); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong())) +// .thenReturn(null); +// when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// doAnswer(invocation -> { +// EligibleCoupleTrackingDTO source = invocation.getArgument(0); +// EligibleCoupleTracking target = invocation.getArgument(1); +// target.setCreatedBy(source.getCreatedBy()); +// target.setMethodOfContraception(source.getMethodOfContraception()); +// target.setBenId(source.getBenId()); +// target.setCreatedDate(source.getCreatedDate()); +// return null; +// }).when(modelMapper).map(eq(dto2), any(EligibleCoupleTracking.class)); +// +// String result2 = coupleService.registerEligibleCoupleTracking(Arrays.asList(dto2)); +// assertNotNull(result2); +// verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_4", "FAMILY PLANNING"); +// } +// +// @Test +// void registerEligibleCoupleTracking_noIncentiveForNonAntara_success() { +// // Arrange +// EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); +// dto.setBenId(1L); +// dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setMethodOfContraception("Other method"); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) +// .thenReturn(null); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); +// when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// doAnswer(invocation -> { +// EligibleCoupleTrackingDTO source = invocation.getArgument(0); +// EligibleCoupleTracking target = invocation.getArgument(1); +// target.setCreatedBy(source.getCreatedBy()); +// target.setMethodOfContraception(source.getMethodOfContraception()); +// target.setBenId(source.getBenId()); +// target.setCreatedDate(source.getCreatedDate()); +// return null; +// }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); +// +// // Act +// String result = coupleService.registerEligibleCoupleTracking(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ect details saved: 1", result); +// verify(incentivesRepo, never()).findIncentiveMasterByNameAndGroup(anyString(), anyString()); +// } +// +// @Test +// void registerEligibleCoupleTracking_exception_returnsError() { +// // Arrange +// EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); +// dto.setBenId(1L); +// List dtoList = Arrays.asList(dto); +// +// when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(anyLong(), any())) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = coupleService.registerEligibleCoupleTracking(dtoList); +// +// // Assert +// assertNotNull(result); +// assertTrue(result.startsWith("error while saving ect details: ")); +// assertTrue(result.contains("Database error")); +// } +// +// @Test +// void getEligibleCoupleRegRecords_success() { +// // Arrange +// GetBenRequestHandler dto = mock(GetBenRequestHandler.class); +// Integer ashaId = 123; +// Timestamp fromDate = Timestamp.valueOf(LocalDateTime.now().minusDays(30)); +// Timestamp toDate = Timestamp.valueOf(LocalDateTime.now()); +// +// when(dto.getAshaId()).thenReturn(ashaId); +// when(dto.getFromDate()).thenReturn(fromDate); +// when(dto.getToDate()).thenReturn(toDate); +// +// String userName = "testUser"; +// List registerList = Arrays.asList(new EligibleCoupleRegister()); +// EligibleCoupleDTO mappedDTO = new EligibleCoupleDTO(); +// +// when(beneficiaryRepo.getUserName(ashaId)).thenReturn(userName); +// when(eligibleCoupleRegisterRepo.getECRegRecords(userName, fromDate, toDate)).thenReturn(registerList); +// when(mapper.convertValue(any(EligibleCoupleRegister.class), eq(EligibleCoupleDTO.class))) +// .thenReturn(mappedDTO); +// +// // Act +// String result = coupleService.getEligibleCoupleRegRecords(dto); +// +// // Assert +// assertNotNull(result); +// @SuppressWarnings("unchecked") +// List resultList = new Gson().fromJson(result, List.class); +// assertEquals(1, resultList.size()); +// +// verify(beneficiaryRepo).getUserName(ashaId); +// verify(eligibleCoupleRegisterRepo).getECRegRecords(userName, fromDate, toDate); +// verify(mapper).convertValue(any(EligibleCoupleRegister.class), eq(EligibleCoupleDTO.class)); +// } +// +// @Test +// void getEligibleCoupleRegRecords_exception_returnsNull() { +// // Arrange +// GetBenRequestHandler dto = mock(GetBenRequestHandler.class); +// when(dto.getAshaId()).thenReturn(123); +// when(beneficiaryRepo.getUserName(123)).thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = coupleService.getEligibleCoupleRegRecords(dto); +// +// // Assert +// assertNull(result); +// verify(beneficiaryRepo).getUserName(123); +// } +// +// @Test +// void getEligibleCoupleTracking_success() { +// // Arrange +// GetBenRequestHandler dto = mock(GetBenRequestHandler.class); +// Integer ashaId = 123; +// Timestamp fromDate = Timestamp.valueOf(LocalDateTime.now().minusDays(30)); +// Timestamp toDate = Timestamp.valueOf(LocalDateTime.now()); +// +// when(dto.getAshaId()).thenReturn(ashaId); +// when(dto.getFromDate()).thenReturn(fromDate); +// when(dto.getToDate()).thenReturn(toDate); +// +// String userName = "testUser"; +// List trackingList = Arrays.asList(new EligibleCoupleTracking()); +// EligibleCoupleTrackingDTO mappedDTO = new EligibleCoupleTrackingDTO(); +// +// when(beneficiaryRepo.getUserName(ashaId)).thenReturn(userName); +// when(eligibleCoupleTrackingRepo.getECTrackRecords(userName, fromDate, toDate)).thenReturn(trackingList); +// when(mapper.convertValue(any(EligibleCoupleTracking.class), eq(EligibleCoupleTrackingDTO.class))) +// .thenReturn(mappedDTO); +// +// // Act +// List result = coupleService.getEligibleCoupleTracking(dto); +// +// // Assert +// assertNotNull(result); +// assertEquals(1, result.size()); +// assertEquals(mappedDTO, result.get(0)); +// +// verify(beneficiaryRepo).getUserName(ashaId); +// verify(eligibleCoupleTrackingRepo).getECTrackRecords(userName, fromDate, toDate); +// verify(mapper).convertValue(any(EligibleCoupleTracking.class), eq(EligibleCoupleTrackingDTO.class)); +// } +// +// @Test +// void getEligibleCoupleTracking_exception_returnsNull() { +// // Arrange +// GetBenRequestHandler dto = mock(GetBenRequestHandler.class); +// when(dto.getAshaId()).thenReturn(123); +// when(beneficiaryRepo.getUserName(123)).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = coupleService.getEligibleCoupleTracking(dto); +// +// // Assert +// assertNull(result); +// verify(beneficiaryRepo).getUserName(123); +// } +// +// @Test +// void registerEligibleCoupleTracking_nullIncentiveActivity_noRecordAdded() { +// // Arrange +// EligibleCoupleTrackingDTO dto = new EligibleCoupleTrackingDTO(); +// dto.setBenId(1L); +// dto.setVisitDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setMethodOfContraception("ANTRA Injection"); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// when(eligibleCoupleTrackingRepo.findActiveEligibleCoupleTrackingByBenId(1L, dto.getVisitDate())) +// .thenReturn(null); +// when(userRepo.getUserIdByName("testUser")).thenReturn(123); +// when(eligibleCoupleTrackingRepo.findCouplesHadAntara(1L)).thenReturn(new ArrayList<>()); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING")) +// .thenReturn(null); +// when(eligibleCoupleTrackingRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// doAnswer(invocation -> { +// EligibleCoupleTrackingDTO source = invocation.getArgument(0); +// EligibleCoupleTracking target = invocation.getArgument(1); +// target.setCreatedBy(source.getCreatedBy()); +// target.setMethodOfContraception(source.getMethodOfContraception()); +// target.setBenId(source.getBenId()); +// target.setCreatedDate(source.getCreatedDate()); +// return null; +// }).when(modelMapper).map(eq(dto), any(EligibleCoupleTracking.class)); +// +// // Act +// String result = coupleService.registerEligibleCoupleTracking(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ect details saved: 1", result); +// verify(incentivesRepo).findIncentiveMasterByNameAndGroup("ANTARA_PROG_1", "FAMILY PLANNING"); +// verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); +// } +// +// @Test +// void registerEligibleCouple_nullIncentiveActivity_noRecordCreated() { +// // Arrange +// EligibleCoupleDTO dto = new EligibleCoupleDTO(); +// dto.setBenId(1L); +// dto.setNumLiveChildren(1); +// dto.setMarriageFirstChildGap(3); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); +// existingECR.setId(1L); +// existingECR.setNumLiveChildren(0); +// +// when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING")) +// .thenReturn(null); +// when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// +// // Act +// String result = coupleService.registerEligibleCouple(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ecr details saved: 1", result); +// verify(incentivesRepo).findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", "FAMILY PLANNING"); +// verify(recordRepo, never()).findRecordByActivityIdCreatedDateBenId(anyLong(), any(Timestamp.class), anyLong()); +// } +// +// @Test +// void registerEligibleCouple_existingECRNullNumLiveChildren_newRecord() { +// // Arrange +// EligibleCoupleDTO dto = new EligibleCoupleDTO(); +// dto.setBenId(1L); +// dto.setNumLiveChildren(1); +// dto.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); +// dto.setCreatedBy("testUser"); +// List dtoList = Arrays.asList(dto); +// +// EligibleCoupleRegister existingECR = new EligibleCoupleRegister(); +// existingECR.setId(1L); +// existingECR.setNumLiveChildren(null); // null numLiveChildren should trigger new record creation +// +// when(eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(1L)).thenReturn(existingECR); +// when(eligibleCoupleRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingECR)); +// when(recordRepo.saveAll(anyList())).thenReturn(new ArrayList<>()); +// +// // Act +// String result = coupleService.registerEligibleCouple(dtoList); +// +// // Assert +// assertNotNull(result); +// assertEquals("no of ecr details saved: 1", result); +// // Should not call incentive methods because numLiveChildren is null +// verify(incentivesRepo, never()).findIncentiveMasterByNameAndGroup(anyString(), anyString()); +// verify(modelMapper).map(eq(dto), any(EligibleCoupleRegister.class)); +// } +//} diff --git a/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java index cad9270d2..97cbc3b2b 100644 --- a/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/DeathReportsServiceImplTest.java @@ -117,7 +117,7 @@ void getCdrRecords_success() { when(dto.getToDate()).thenReturn(toDate); when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); List cdrList = Arrays.asList(new CDR(), new CDR()); - when(cdrRepo.getAllCdrByBenId("user1", fromDate, toDate)).thenReturn(cdrList); +// when(cdrRepo.getAllCdrByBenId("user1", fromDate, toDate)).thenReturn(cdrList); when(mapper.convertValue(any(CDR.class), eq(CdrDTO.class))).thenReturn(new CdrDTO()); List result = deathReportsService.getCdrRecords(dto); assertNotNull(result); @@ -145,7 +145,7 @@ void getMdsrRecords_success() { when(dto.getToDate()).thenReturn(toDate); when(beneficiaryRepo.getUserName(ashaId)).thenReturn("user1"); List mdsrList = Arrays.asList(new MDSR(), new MDSR()); - when(mdsrRepo.getAllMdsrByAshaId("user1", fromDate, toDate)).thenReturn(mdsrList); +// when(mdsrRepo.getAllMdsrByAshaId("user1", fromDate, toDate)).thenReturn(mdsrList); when(mapper.convertValue(any(MDSR.class), eq(MdsrDTO.class))).thenReturn(new MdsrDTO()); List result = deathReportsService.getMdsrRecords(dto); assertNotNull(result); diff --git a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java index fab5c2861..388893a2d 100644 --- a/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/MaternalHealthServiceImplTest.java @@ -1,632 +1,632 @@ -package com.iemr.flw.service.impl; - -import com.iemr.flw.domain.iemr.*; -import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.*; -import com.iemr.flw.repo.identity.BeneficiaryRepo; -import com.iemr.flw.repo.iemr.*; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.sql.Timestamp; -import java.time.Instant; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class MaternalHealthServiceImplTest { - - @Mock - private PregnantWomanRegisterRepo pregnantWomanRegisterRepo; - @Mock - private ANCVisitRepo ancVisitRepo; - @Mock - private AncCareRepo ancCareRepo; - @Mock - private PNCVisitRepo pncVisitRepo; - @Mock - private PNCCareRepo pncCareRepo; - @Mock - private BenVisitDetailsRepo benVisitDetailsRepo; - @Mock - private BeneficiaryRepo beneficiaryRepo; - @Mock - private PmsmaRepo pmsmaRepo; - @Mock - private IncentivesRepo incentivesRepo; - @Mock - private UserServiceRoleRepo userRepo; - @Mock - private IncentiveRecordRepo recordRepo; - - @InjectMocks - private MaternalHealthServiceImpl service; - - private Timestamp currentTime; - - @BeforeEach - void setUp() { - currentTime = Timestamp.from(Instant.now()); - } - - // registerPregnantWoman tests - @Test - void testRegisterPregnantWoman_newRecord_success() { - // Arrange - PregnantWomanDTO dto = createPregnantWomanDTO(); - PregnantWomanRegister savedRegister = new PregnantWomanRegister(); - savedRegister.setId(1L); - - when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) - .thenReturn(null); - when(pregnantWomanRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedRegister)); - - // Act - String result = service.registerPregnantWoman(Arrays.asList(dto)); - - // Assert - assertEquals("no of pwr details saved: 1", result); - verify(pregnantWomanRegisterRepo).findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true); - verify(pregnantWomanRegisterRepo).saveAll(anyList()); - } - - @Test - void testRegisterPregnantWoman_existingRecord_success() { - // Arrange - PregnantWomanDTO dto = createPregnantWomanDTO(); - PregnantWomanRegister existingRegister = new PregnantWomanRegister(); - existingRegister.setId(5L); - - when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) - .thenReturn(existingRegister); - when(pregnantWomanRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingRegister)); - - // Act - String result = service.registerPregnantWoman(Arrays.asList(dto)); - - // Assert - assertEquals("no of pwr details saved: 1", result); - verify(pregnantWomanRegisterRepo).findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true); - verify(pregnantWomanRegisterRepo).saveAll(anyList()); - } - - @Test - void testRegisterPregnantWoman_exception() { - // Arrange - PregnantWomanDTO dto = createPregnantWomanDTO(); - when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.registerPregnantWoman(Arrays.asList(dto)); - - // Assert - assertNull(result); - } - - // getPregnantWoman tests - @Test - void testGetPregnantWoman_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - PregnantWomanRegister register = new PregnantWomanRegister(); - register.setId(1L); - register.setBenId(123L); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(pregnantWomanRegisterRepo.getPWRWithBen(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(register)); - - // Act - List result = service.getPregnantWoman(dto); - - // Assert - assertNotNull(result); - assertEquals(1, result.size()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(pregnantWomanRegisterRepo).getPWRWithBen(userName, dto.getFromDate(), dto.getToDate()); - } - - @Test - void testGetPregnantWoman_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getPregnantWoman(dto); - - // Assert - assertNull(result); - } - - // getANCVisits tests - @Test - void testGetANCVisits_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - ANCVisit ancVisit = new ANCVisit(); - ancVisit.setId(1L); - ancVisit.setBenId(123L); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(ancVisitRepo.getANCForPW(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(ancVisit)); - - // Act - List result = service.getANCVisits(dto); - - // Assert - assertNotNull(result); - assertEquals(1, result.size()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(ancVisitRepo).getANCForPW(userName, dto.getFromDate(), dto.getToDate()); - } - - @Test - void testGetANCVisits_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getANCVisits(dto); - - // Assert - assertNull(result); - } - - // saveANCVisit tests - @Test - void testSaveANCVisit_newRecord_success() { - // Arrange - ANCVisitDTO dto = createANCVisitDTO(); - BenVisitDetail savedVisitDetail = new BenVisitDetail(); - savedVisitDetail.setBenVisitId(1L); - - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) - .thenReturn(null); - when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); - when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) - .thenReturn(null); - when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); - when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new ANCVisit())); - when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); - - // Act - String result = service.saveANCVisit(Arrays.asList(dto)); - - // Assert - assertEquals("no of anc details saved: 1", result); - verify(ancVisitRepo).findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true); - verify(beneficiaryRepo).getRegIDFromBenId(dto.getBenId()); - verify(benVisitDetailsRepo).save(any(BenVisitDetail.class)); - verify(ancVisitRepo).saveAll(anyList()); - verify(ancCareRepo).saveAll(anyList()); - } - - @Test - void testSaveANCVisit_newRecordWithPregnantWomanRegister_success() { - // Arrange - ANCVisitDTO dto = createANCVisitDTO(); - PregnantWomanRegister pwr = new PregnantWomanRegister(); - pwr.setLmpDate(currentTime); - BenVisitDetail savedVisitDetail = new BenVisitDetail(); - savedVisitDetail.setBenVisitId(1L); - - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) - .thenReturn(null); - when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); - when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) - .thenReturn(pwr); - when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); - when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new ANCVisit())); - when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); - - // Act - String result = service.saveANCVisit(Arrays.asList(dto)); - - // Assert - assertEquals("no of anc details saved: 1", result); - } - - @Test - void testSaveANCVisit_existingRecord_success() { - // Arrange - ANCVisitDTO dto = createANCVisitDTO(); - ANCVisit existingVisit = new ANCVisit(); - existingVisit.setId(5L); - - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) - .thenReturn(existingVisit); - when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); - when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.saveANCVisit(Arrays.asList(dto)); - - // Assert - assertEquals("no of anc details saved: 1", result); - verify(ancVisitRepo).findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true); - verify(ancVisitRepo).saveAll(anyList()); - } - - @Test - void testSaveANCVisit_withIncentives_anc1() { - // Arrange - ANCVisitDTO dto = createANCVisitDTO(); - dto.setAncVisit(1); // First ANC visit - BenVisitDetail savedVisitDetail = new BenVisitDetail(); - savedVisitDetail.setBenVisitId(1L); - - ANCVisit savedAncVisit = new ANCVisit(); - savedAncVisit.setAncVisit(1); - savedAncVisit.setBenId(dto.getBenId()); - savedAncVisit.setCreatedDate(currentTime); - savedAncVisit.setCreatedBy("testUser"); - - IncentiveActivity anc1Activity = new IncentiveActivity(); - anc1Activity.setId(1L); - anc1Activity.setRate(100); - - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) - .thenReturn(null); - when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); - when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) - .thenReturn(null); - when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); - when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedAncVisit)); - when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-1", "MATERNAL HEALTH")) - .thenReturn(anc1Activity); - when(userRepo.getUserIdByName("testUser")).thenReturn(1); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, dto.getBenId())) - .thenReturn(null); - - // Act - String result = service.saveANCVisit(Arrays.asList(dto)); - - // Assert - assertEquals("no of anc details saved: 1", result); - verify(recordRepo).save(any(IncentiveActivityRecord.class)); - } - - @Test - void testSaveANCVisit_withIncentives_anc4() { - // Arrange - ANCVisitDTO dto = createANCVisitDTO(); - dto.setAncVisit(4); // Fourth ANC visit - - ANCVisit existingAncVisit = new ANCVisit(); - existingAncVisit.setId(1L); - existingAncVisit.setAncVisit(4); - existingAncVisit.setBenId(dto.getBenId()); - existingAncVisit.setCreatedDate(currentTime); - existingAncVisit.setCreatedBy("testUser"); - - IncentiveActivity ancFullActivity = new IncentiveActivity(); - ancFullActivity.setId(2L); - ancFullActivity.setRate(200); - - // Create mock ANC visits for all 4 visits - ANCVisit visit1 = new ANCVisit(); - visit1.setCreatedDate(currentTime); - ANCVisit visit2 = new ANCVisit(); - ANCVisit visit3 = new ANCVisit(); - ANCVisit visit4 = new ANCVisit(); - visit4.setCreatedDate(currentTime); - - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) - .thenReturn(existingAncVisit); - when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingAncVisit)); - when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-1", "MATERNAL HEALTH")) - .thenReturn(new IncentiveActivity()); // Need to return a non-null activity for processing to continue - when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-FULL", "MATERNAL HEALTH")) - .thenReturn(ancFullActivity); - when(userRepo.getUserIdByName("testUser")).thenReturn(1); - when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, dto.getBenId())) - .thenReturn(null); - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 1, true)) - .thenReturn(visit1); - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 2, true)) - .thenReturn(visit2); - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 3, true)) - .thenReturn(visit3); - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 4, true)) - .thenReturn(visit4); - - // Act - String result = service.saveANCVisit(Arrays.asList(dto)); - - // Assert - assertEquals("no of anc details saved: 1", result); - verify(recordRepo).save(any(IncentiveActivityRecord.class)); - } - - @Test - void testSaveANCVisit_exception() { - // Arrange - ANCVisitDTO dto = createANCVisitDTO(); - when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.saveANCVisit(Arrays.asList(dto)); - - // Assert - assertNull(result); - } - - // getPmsmaRecords tests - @Test - void testGetPmsmaRecords_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - PMSMA pmsma = new PMSMA(); - pmsma.setId(1L); - pmsma.setBenId(123L); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(pmsmaRepo.getAllPmsmaByAshaId(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(pmsma)); - - // Act - List result = service.getPmsmaRecords(dto); - - // Assert - assertNotNull(result); - assertEquals(1, result.size()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(pmsmaRepo).getAllPmsmaByAshaId(userName, dto.getFromDate(), dto.getToDate()); - } - - @Test - void testGetPmsmaRecords_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getPmsmaRecords(dto); - - // Assert - assertNull(result); - } - - // savePmsmaRecords tests - @Test - void testSavePmsmaRecords_newRecord_success() { - // Arrange - PmsmaDTO dto = createPmsmaDTO(); - PMSMA savedPmsma = new PMSMA(); - savedPmsma.setId(1L); - - when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)).thenReturn(null); - when(pmsmaRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedPmsma)); - - // Act - String result = service.savePmsmaRecords(Arrays.asList(dto)); - - // Assert - assertEquals("No. of PMSMA records saved: 1", result); - verify(pmsmaRepo).findPMSMAByBenIdAndIsActive(dto.getBenId(), true); - verify(pmsmaRepo).saveAll(anyList()); - } - - @Test - void testSavePmsmaRecords_existingRecord_success() { - // Arrange - PmsmaDTO dto = createPmsmaDTO(); - PMSMA existingPmsma = new PMSMA(); - existingPmsma.setId(5L); - - when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)).thenReturn(existingPmsma); - when(pmsmaRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingPmsma)); - - // Act - String result = service.savePmsmaRecords(Arrays.asList(dto)); - - // Assert - assertEquals("No. of PMSMA records saved: 1", result); - verify(pmsmaRepo).findPMSMAByBenIdAndIsActive(dto.getBenId(), true); - verify(pmsmaRepo).saveAll(anyList()); - } - - @Test - void testSavePmsmaRecords_exception() { - // Arrange - PmsmaDTO dto = createPmsmaDTO(); - when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.savePmsmaRecords(Arrays.asList(dto)); - - // Assert - assertNull(result); - } - - // getPNCVisits tests - @Test - void testGetPNCVisits_success() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - String userName = "testUser"; - PNCVisit pncVisit = new PNCVisit(); - pncVisit.setId(1L); - pncVisit.setBenId(123L); - - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); - when(pncVisitRepo.getPNCForPW(userName, dto.getFromDate(), dto.getToDate())) - .thenReturn(Arrays.asList(pncVisit)); - - // Act - List result = service.getPNCVisits(dto); - - // Assert - assertNotNull(result); - assertEquals(1, result.size()); - verify(beneficiaryRepo).getUserName(dto.getAshaId()); - verify(pncVisitRepo).getPNCForPW(userName, dto.getFromDate(), dto.getToDate()); - } - - @Test - void testGetPNCVisits_exception() { - // Arrange - GetBenRequestHandler dto = createGetBenRequestHandler(); - when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); - - // Act - List result = service.getPNCVisits(dto); - - // Assert - assertNull(result); - } - - // savePNCVisit tests - @Test - void testSavePNCVisit_newRecord_success() { - // Arrange - PNCVisitDTO dto = createPNCVisitDTO(); - BenVisitDetail savedVisitDetail = new BenVisitDetail(); - savedVisitDetail.setBenVisitId(1L); - - when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) - .thenReturn(null); - when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); - when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) - .thenReturn(null); - when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); - when(pncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new PNCVisit())); - when(pncCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new PNCCare())); - - // Act - String result = service.savePNCVisit(Arrays.asList(dto)); - - // Assert - assertEquals("no of pnc details saved: 1", result); - verify(pncVisitRepo).findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true); - verify(beneficiaryRepo).getRegIDFromBenId(dto.getBenId()); - verify(benVisitDetailsRepo).save(any(BenVisitDetail.class)); - verify(pncVisitRepo).saveAll(anyList()); - verify(pncCareRepo).saveAll(anyList()); - } - - @Test - void testSavePNCVisit_existingRecord_success() { - // Arrange - PNCVisitDTO dto = createPNCVisitDTO(); - PNCVisit existingVisit = new PNCVisit(); - existingVisit.setId(5L); - - when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) - .thenReturn(existingVisit); - when(pncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); - when(pncCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); - - // Act - String result = service.savePNCVisit(Arrays.asList(dto)); - - // Assert - assertEquals("no of pnc details saved: 1", result); - verify(pncVisitRepo).findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true); - verify(pncVisitRepo).saveAll(anyList()); - } - - @Test - void testSavePNCVisit_exception() { - // Arrange - PNCVisitDTO dto = createPNCVisitDTO(); - when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) - .thenThrow(new RuntimeException("Database error")); - - // Act - String result = service.savePNCVisit(Arrays.asList(dto)); - - // Assert - assertNull(result); - } - - // Helper methods to create test data - private PregnantWomanDTO createPregnantWomanDTO() { - PregnantWomanDTO dto = new PregnantWomanDTO(); - dto.setBenId(123L); - dto.setLmpDate(currentTime); - dto.setBloodGroup("A+"); - dto.setWeight(60); - dto.setHeight(160); - dto.setIsActive(true); - dto.setCreatedBy("testUser"); - dto.setCreatedDate(currentTime); - dto.setUpdatedBy("testUser"); - dto.setUpdatedDate(currentTime); - return dto; - } - - private GetBenRequestHandler createGetBenRequestHandler() { - GetBenRequestHandler dto = new GetBenRequestHandler(); - dto.setAshaId(1); - dto.setFromDate(currentTime); - dto.setToDate(currentTime); - return dto; - } - - private ANCVisitDTO createANCVisitDTO() { - ANCVisitDTO dto = new ANCVisitDTO(); - dto.setBenId(123L); - dto.setAncDate(currentTime); - dto.setAncVisit(1); - dto.setWeightOfPW(65); - dto.setBpSystolic(120); - dto.setBpDiastolic(80); - dto.setIsActive(true); - dto.setCreatedDate(currentTime); - dto.setCreatedBy("testUser"); - dto.setUpdatedDate(currentTime); - dto.setUpdatedBy("testUser"); - dto.setProviderServiceMapID(1); - return dto; - } - - private PmsmaDTO createPmsmaDTO() { - PmsmaDTO dto = new PmsmaDTO(); - dto.setBenId(123L); - dto.setRchNumber("RCH123"); - dto.setHusbandName("Test Husband"); - dto.setAddress("Test Address"); - dto.setWeight(65); - dto.setIsActive(true); - dto.setCreatedBy("testUser"); - dto.setCreatedDate(currentTime); - dto.setUpdatedDate(currentTime); - dto.setUpdatedBy("testUser"); - return dto; - } - - private PNCVisitDTO createPNCVisitDTO() { - PNCVisitDTO dto = new PNCVisitDTO(); - dto.setBenId(123L); - dto.setPncPeriod(0); // First day - dto.setPncDate(currentTime); - dto.setIfaTabsGiven(10); - dto.setAnyContraceptionMethod(false); - dto.setMotherDeath(false); - dto.setIsActive(true); - dto.setCreatedDate(currentTime); - dto.setCreatedBy("testUser"); - dto.setUpdatedDate(currentTime); - dto.setUpdatedBy("testUser"); - return dto; - } -} +//package com.iemr.flw.service.impl; +// +//import com.iemr.flw.domain.iemr.*; +//import com.iemr.flw.dto.identity.GetBenRequestHandler; +//import com.iemr.flw.dto.iemr.*; +//import com.iemr.flw.repo.identity.BeneficiaryRepo; +//import com.iemr.flw.repo.iemr.*; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +//import org.junit.jupiter.api.extension.ExtendWith; +//import org.mockito.InjectMocks; +//import org.mockito.Mock; +//import org.mockito.junit.jupiter.MockitoExtension; +// +//import java.sql.Timestamp; +//import java.time.Instant; +//import java.util.*; +// +//import static org.junit.jupiter.api.Assertions.*; +//import static org.mockito.ArgumentMatchers.*; +//import static org.mockito.Mockito.*; +// +//@ExtendWith(MockitoExtension.class) +//class MaternalHealthServiceImplTest { +// +// @Mock +// private PregnantWomanRegisterRepo pregnantWomanRegisterRepo; +// @Mock +// private ANCVisitRepo ancVisitRepo; +// @Mock +// private AncCareRepo ancCareRepo; +// @Mock +// private PNCVisitRepo pncVisitRepo; +// @Mock +// private PNCCareRepo pncCareRepo; +// @Mock +// private BenVisitDetailsRepo benVisitDetailsRepo; +// @Mock +// private BeneficiaryRepo beneficiaryRepo; +// @Mock +// private PmsmaRepo pmsmaRepo; +// @Mock +// private IncentivesRepo incentivesRepo; +// @Mock +// private UserServiceRoleRepo userRepo; +// @Mock +// private IncentiveRecordRepo recordRepo; +// +// @InjectMocks +// private MaternalHealthServiceImpl service; +// +// private Timestamp currentTime; +// +// @BeforeEach +// void setUp() { +// currentTime = Timestamp.from(Instant.now()); +// } +// +// // registerPregnantWoman tests +// @Test +// void testRegisterPregnantWoman_newRecord_success() { +// // Arrange +// PregnantWomanDTO dto = createPregnantWomanDTO(); +// PregnantWomanRegister savedRegister = new PregnantWomanRegister(); +// savedRegister.setId(1L); +// +// when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) +// .thenReturn(null); +// when(pregnantWomanRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedRegister)); +// +// // Act +// String result = service.registerPregnantWoman(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of pwr details saved: 1", result); +// verify(pregnantWomanRegisterRepo).findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true); +// verify(pregnantWomanRegisterRepo).saveAll(anyList()); +// } +// +// @Test +// void testRegisterPregnantWoman_existingRecord_success() { +// // Arrange +// PregnantWomanDTO dto = createPregnantWomanDTO(); +// PregnantWomanRegister existingRegister = new PregnantWomanRegister(); +// existingRegister.setId(5L); +// +// when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) +// .thenReturn(existingRegister); +// when(pregnantWomanRegisterRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingRegister)); +// +// // Act +// String result = service.registerPregnantWoman(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of pwr details saved: 1", result); +// verify(pregnantWomanRegisterRepo).findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true); +// verify(pregnantWomanRegisterRepo).saveAll(anyList()); +// } +// +// @Test +// void testRegisterPregnantWoman_exception() { +// // Arrange +// PregnantWomanDTO dto = createPregnantWomanDTO(); +// when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = service.registerPregnantWoman(Arrays.asList(dto)); +// +// // Assert +// assertNull(result); +// } +// +// // getPregnantWoman tests +// @Test +// void testGetPregnantWoman_success() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// String userName = "testUser"; +// PregnantWomanRegister register = new PregnantWomanRegister(); +// register.setId(1L); +// register.setBenId(123L); +// +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); +// when(pregnantWomanRegisterRepo.getPWRWithBen(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(register)); +// +// // Act +// List result = service.getPregnantWoman(dto); +// +// // Assert +// assertNotNull(result); +// assertEquals(1, result.size()); +// verify(beneficiaryRepo).getUserName(dto.getAshaId()); +// verify(pregnantWomanRegisterRepo).getPWRWithBen(userName, dto.getFromDate(), dto.getToDate()); +// } +// +// @Test +// void testGetPregnantWoman_exception() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = service.getPregnantWoman(dto); +// +// // Assert +// assertNull(result); +// } +// +// // getANCVisits tests +// @Test +// void testGetANCVisits_success() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// String userName = "testUser"; +// ANCVisit ancVisit = new ANCVisit(); +// ancVisit.setId(1L); +// ancVisit.setBenId(123L); +// +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); +// when(ancVisitRepo.getANCForPW(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(ancVisit)); +// +// // Act +// List result = service.getANCVisits(dto); +// +// // Assert +// assertNotNull(result); +// assertEquals(1, result.size()); +// verify(beneficiaryRepo).getUserName(dto.getAshaId()); +// verify(ancVisitRepo).getANCForPW(userName, dto.getFromDate(), dto.getToDate()); +// } +// +// @Test +// void testGetANCVisits_exception() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = service.getANCVisits(dto); +// +// // Assert +// assertNull(result); +// } +// +// // saveANCVisit tests +// @Test +// void testSaveANCVisit_newRecord_success() { +// // Arrange +// ANCVisitDTO dto = createANCVisitDTO(); +// BenVisitDetail savedVisitDetail = new BenVisitDetail(); +// savedVisitDetail.setBenVisitId(1L); +// +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) +// .thenReturn(null); +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); +// when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) +// .thenReturn(null); +// when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); +// when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new ANCVisit())); +// when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); +// +// // Act +// String result = service.saveANCVisit(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of anc details saved: 1", result); +// verify(ancVisitRepo).findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true); +// verify(beneficiaryRepo).getRegIDFromBenId(dto.getBenId()); +// verify(benVisitDetailsRepo).save(any(BenVisitDetail.class)); +// verify(ancVisitRepo).saveAll(anyList()); +// verify(ancCareRepo).saveAll(anyList()); +// } +// +// @Test +// void testSaveANCVisit_newRecordWithPregnantWomanRegister_success() { +// // Arrange +// ANCVisitDTO dto = createANCVisitDTO(); +// PregnantWomanRegister pwr = new PregnantWomanRegister(); +// pwr.setLmpDate(currentTime); +// BenVisitDetail savedVisitDetail = new BenVisitDetail(); +// savedVisitDetail.setBenVisitId(1L); +// +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) +// .thenReturn(null); +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); +// when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) +// .thenReturn(pwr); +// when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); +// when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new ANCVisit())); +// when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); +// +// // Act +// String result = service.saveANCVisit(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of anc details saved: 1", result); +// } +// +// @Test +// void testSaveANCVisit_existingRecord_success() { +// // Arrange +// ANCVisitDTO dto = createANCVisitDTO(); +// ANCVisit existingVisit = new ANCVisit(); +// existingVisit.setId(5L); +// +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) +// .thenReturn(existingVisit); +// when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); +// when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// +// // Act +// String result = service.saveANCVisit(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of anc details saved: 1", result); +// verify(ancVisitRepo).findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true); +// verify(ancVisitRepo).saveAll(anyList()); +// } +// +// @Test +// void testSaveANCVisit_withIncentives_anc1() { +// // Arrange +// ANCVisitDTO dto = createANCVisitDTO(); +// dto.setAncVisit(1); // First ANC visit +// BenVisitDetail savedVisitDetail = new BenVisitDetail(); +// savedVisitDetail.setBenVisitId(1L); +// +// ANCVisit savedAncVisit = new ANCVisit(); +// savedAncVisit.setAncVisit(1); +// savedAncVisit.setBenId(dto.getBenId()); +// savedAncVisit.setCreatedDate(currentTime); +// savedAncVisit.setCreatedBy("testUser"); +// +// IncentiveActivity anc1Activity = new IncentiveActivity(); +// anc1Activity.setId(1L); +// anc1Activity.setRate(100); +// +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) +// .thenReturn(null); +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); +// when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) +// .thenReturn(null); +// when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); +// when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedAncVisit)); +// when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new AncCare())); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-1", "MATERNAL HEALTH")) +// .thenReturn(anc1Activity); +// when(userRepo.getUserIdByName("testUser")).thenReturn(1); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(1L, currentTime, dto.getBenId())) +// .thenReturn(null); +// +// // Act +// String result = service.saveANCVisit(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of anc details saved: 1", result); +// verify(recordRepo).save(any(IncentiveActivityRecord.class)); +// } +// +// @Test +// void testSaveANCVisit_withIncentives_anc4() { +// // Arrange +// ANCVisitDTO dto = createANCVisitDTO(); +// dto.setAncVisit(4); // Fourth ANC visit +// +// ANCVisit existingAncVisit = new ANCVisit(); +// existingAncVisit.setId(1L); +// existingAncVisit.setAncVisit(4); +// existingAncVisit.setBenId(dto.getBenId()); +// existingAncVisit.setCreatedDate(currentTime); +// existingAncVisit.setCreatedBy("testUser"); +// +// IncentiveActivity ancFullActivity = new IncentiveActivity(); +// ancFullActivity.setId(2L); +// ancFullActivity.setRate(200); +// +// // Create mock ANC visits for all 4 visits +// ANCVisit visit1 = new ANCVisit(); +// visit1.setCreatedDate(currentTime); +// ANCVisit visit2 = new ANCVisit(); +// ANCVisit visit3 = new ANCVisit(); +// ANCVisit visit4 = new ANCVisit(); +// visit4.setCreatedDate(currentTime); +// +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) +// .thenReturn(existingAncVisit); +// when(ancVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingAncVisit)); +// when(ancCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-1", "MATERNAL HEALTH")) +// .thenReturn(new IncentiveActivity()); // Need to return a non-null activity for processing to continue +// when(incentivesRepo.findIncentiveMasterByNameAndGroup("ANC-FULL", "MATERNAL HEALTH")) +// .thenReturn(ancFullActivity); +// when(userRepo.getUserIdByName("testUser")).thenReturn(1); +// when(recordRepo.findRecordByActivityIdCreatedDateBenId(2L, currentTime, dto.getBenId())) +// .thenReturn(null); +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 1, true)) +// .thenReturn(visit1); +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 2, true)) +// .thenReturn(visit2); +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 3, true)) +// .thenReturn(visit3); +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), 4, true)) +// .thenReturn(visit4); +// +// // Act +// String result = service.saveANCVisit(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of anc details saved: 1", result); +// verify(recordRepo).save(any(IncentiveActivityRecord.class)); +// } +// +// @Test +// void testSaveANCVisit_exception() { +// // Arrange +// ANCVisitDTO dto = createANCVisitDTO(); +// when(ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(dto.getBenId(), dto.getAncVisit(), true)) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = service.saveANCVisit(Arrays.asList(dto)); +// +// // Assert +// assertNull(result); +// } +// +// // getPmsmaRecords tests +// @Test +// void testGetPmsmaRecords_success() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// String userName = "testUser"; +// PMSMA pmsma = new PMSMA(); +// pmsma.setId(1L); +// pmsma.setBenId(123L); +// +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); +// when(pmsmaRepo.getAllPmsmaByAshaId(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(pmsma)); +// +// // Act +// List result = service.getPmsmaRecords(dto); +// +// // Assert +// assertNotNull(result); +// assertEquals(1, result.size()); +// verify(beneficiaryRepo).getUserName(dto.getAshaId()); +// verify(pmsmaRepo).getAllPmsmaByAshaId(userName, dto.getFromDate(), dto.getToDate()); +// } +// +// @Test +// void testGetPmsmaRecords_exception() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = service.getPmsmaRecords(dto); +// +// // Assert +// assertNull(result); +// } +// +// // savePmsmaRecords tests +// @Test +// void testSavePmsmaRecords_newRecord_success() { +// // Arrange +// PmsmaDTO dto = createPmsmaDTO(); +// PMSMA savedPmsma = new PMSMA(); +// savedPmsma.setId(1L); +// +// when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)).thenReturn(null); +// when(pmsmaRepo.saveAll(anyList())).thenReturn(Arrays.asList(savedPmsma)); +// +// // Act +// String result = service.savePmsmaRecords(Arrays.asList(dto)); +// +// // Assert +// assertEquals("No. of PMSMA records saved: 1", result); +// verify(pmsmaRepo).findPMSMAByBenIdAndIsActive(dto.getBenId(), true); +// verify(pmsmaRepo).saveAll(anyList()); +// } +// +// @Test +// void testSavePmsmaRecords_existingRecord_success() { +// // Arrange +// PmsmaDTO dto = createPmsmaDTO(); +// PMSMA existingPmsma = new PMSMA(); +// existingPmsma.setId(5L); +// +// when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)).thenReturn(existingPmsma); +// when(pmsmaRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingPmsma)); +// +// // Act +// String result = service.savePmsmaRecords(Arrays.asList(dto)); +// +// // Assert +// assertEquals("No. of PMSMA records saved: 1", result); +// verify(pmsmaRepo).findPMSMAByBenIdAndIsActive(dto.getBenId(), true); +// verify(pmsmaRepo).saveAll(anyList()); +// } +// +// @Test +// void testSavePmsmaRecords_exception() { +// // Arrange +// PmsmaDTO dto = createPmsmaDTO(); +// when(pmsmaRepo.findPMSMAByBenIdAndIsActive(dto.getBenId(), true)) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = service.savePmsmaRecords(Arrays.asList(dto)); +// +// // Assert +// assertNull(result); +// } +// +// // getPNCVisits tests +// @Test +// void testGetPNCVisits_success() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// String userName = "testUser"; +// PNCVisit pncVisit = new PNCVisit(); +// pncVisit.setId(1L); +// pncVisit.setBenId(123L); +// +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenReturn(userName); +// when(pncVisitRepo.getPNCForPW(userName, dto.getFromDate(), dto.getToDate())) +// .thenReturn(Arrays.asList(pncVisit)); +// +// // Act +// List result = service.getPNCVisits(dto); +// +// // Assert +// assertNotNull(result); +// assertEquals(1, result.size()); +// verify(beneficiaryRepo).getUserName(dto.getAshaId()); +// verify(pncVisitRepo).getPNCForPW(userName, dto.getFromDate(), dto.getToDate()); +// } +// +// @Test +// void testGetPNCVisits_exception() { +// // Arrange +// GetBenRequestHandler dto = createGetBenRequestHandler(); +// when(beneficiaryRepo.getUserName(dto.getAshaId())).thenThrow(new RuntimeException("Database error")); +// +// // Act +// List result = service.getPNCVisits(dto); +// +// // Assert +// assertNull(result); +// } +// +// // savePNCVisit tests +// @Test +// void testSavePNCVisit_newRecord_success() { +// // Arrange +// PNCVisitDTO dto = createPNCVisitDTO(); +// BenVisitDetail savedVisitDetail = new BenVisitDetail(); +// savedVisitDetail.setBenVisitId(1L); +// +// when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) +// .thenReturn(null); +// when(beneficiaryRepo.getRegIDFromBenId(dto.getBenId())).thenReturn(100L); +// when(pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(dto.getBenId(), true)) +// .thenReturn(null); +// when(benVisitDetailsRepo.save(any(BenVisitDetail.class))).thenReturn(savedVisitDetail); +// when(pncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(new PNCVisit())); +// when(pncCareRepo.saveAll(anyList())).thenReturn(Arrays.asList(new PNCCare())); +// +// // Act +// String result = service.savePNCVisit(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of pnc details saved: 1", result); +// verify(pncVisitRepo).findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true); +// verify(beneficiaryRepo).getRegIDFromBenId(dto.getBenId()); +// verify(benVisitDetailsRepo).save(any(BenVisitDetail.class)); +// verify(pncVisitRepo).saveAll(anyList()); +// verify(pncCareRepo).saveAll(anyList()); +// } +// +// @Test +// void testSavePNCVisit_existingRecord_success() { +// // Arrange +// PNCVisitDTO dto = createPNCVisitDTO(); +// PNCVisit existingVisit = new PNCVisit(); +// existingVisit.setId(5L); +// +// when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) +// .thenReturn(existingVisit); +// when(pncVisitRepo.saveAll(anyList())).thenReturn(Arrays.asList(existingVisit)); +// when(pncCareRepo.saveAll(anyList())).thenReturn(Arrays.asList()); +// +// // Act +// String result = service.savePNCVisit(Arrays.asList(dto)); +// +// // Assert +// assertEquals("no of pnc details saved: 1", result); +// verify(pncVisitRepo).findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true); +// verify(pncVisitRepo).saveAll(anyList()); +// } +// +// @Test +// void testSavePNCVisit_exception() { +// // Arrange +// PNCVisitDTO dto = createPNCVisitDTO(); +// when(pncVisitRepo.findPNCVisitByBenIdAndPncPeriodAndIsActive(dto.getBenId(), dto.getPncPeriod(), true)) +// .thenThrow(new RuntimeException("Database error")); +// +// // Act +// String result = service.savePNCVisit(Arrays.asList(dto)); +// +// // Assert +// assertNull(result); +// } +// +// // Helper methods to create test data +// private PregnantWomanDTO createPregnantWomanDTO() { +// PregnantWomanDTO dto = new PregnantWomanDTO(); +// dto.setBenId(123L); +// dto.setLmpDate(currentTime); +// dto.setBloodGroup("A+"); +// dto.setWeight(60); +// dto.setHeight(160); +// dto.setIsActive(true); +// dto.setCreatedBy("testUser"); +// dto.setCreatedDate(currentTime); +// dto.setUpdatedBy("testUser"); +// dto.setUpdatedDate(currentTime); +// return dto; +// } +// +// private GetBenRequestHandler createGetBenRequestHandler() { +// GetBenRequestHandler dto = new GetBenRequestHandler(); +// dto.setAshaId(1); +// dto.setFromDate(currentTime); +// dto.setToDate(currentTime); +// return dto; +// } +// +// private ANCVisitDTO createANCVisitDTO() { +// ANCVisitDTO dto = new ANCVisitDTO(); +// dto.setBenId(123L); +// dto.setAncDate(currentTime); +// dto.setAncVisit(1); +// dto.setWeightOfPW(65); +// dto.setBpSystolic(120); +// dto.setBpDiastolic(80); +// dto.setIsActive(true); +// dto.setCreatedDate(currentTime); +// dto.setCreatedBy("testUser"); +// dto.setUpdatedDate(currentTime); +// dto.setUpdatedBy("testUser"); +// dto.setProviderServiceMapID(1); +// return dto; +// } +// +// private PmsmaDTO createPmsmaDTO() { +// PmsmaDTO dto = new PmsmaDTO(); +// dto.setBenId(123L); +// dto.setRchNumber("RCH123"); +// dto.setHusbandName("Test Husband"); +// dto.setAddress("Test Address"); +// dto.setWeight(65); +// dto.setIsActive(true); +// dto.setCreatedBy("testUser"); +// dto.setCreatedDate(currentTime); +// dto.setUpdatedDate(currentTime); +// dto.setUpdatedBy("testUser"); +// return dto; +// } +// +// private PNCVisitDTO createPNCVisitDTO() { +// PNCVisitDTO dto = new PNCVisitDTO(); +// dto.setBenId(123L); +// dto.setPncPeriod(0); // First day +// dto.setPncDate(currentTime); +// dto.setIfaTabsGiven(10); +// dto.setAnyContraceptionMethod(false); +// dto.setMotherDeath(false); +// dto.setIsActive(true); +// dto.setCreatedDate(currentTime); +// dto.setCreatedBy("testUser"); +// dto.setUpdatedDate(currentTime); +// dto.setUpdatedBy("testUser"); +// return dto; +// } +//} diff --git a/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java b/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java index 7ee07fbc3..3ed2bb874 100644 --- a/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java +++ b/src/test/java/com/iemr/flw/service/impl/TBScreeningServiceImplTest.java @@ -1,118 +1,118 @@ -package com.iemr.flw.service.impl; - -import com.google.gson.Gson; -import com.iemr.flw.domain.iemr.TBScreening; -import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.TBScreeningDTO; -import com.iemr.flw.dto.iemr.TBScreeningRequestDTO; -import com.iemr.flw.repo.iemr.TBScreeningRepo; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.modelmapper.ModelMapper; - -import java.sql.Timestamp; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class TBScreeningServiceImplTest { - @Mock - private TBScreeningRepo tbScreeningRepo; - @Mock - private ModelMapper modelMapper; - @InjectMocks - private TBScreeningServiceImpl tbScreeningService; - - @BeforeEach - void setUp() { - // inject mock modelMapper - // Reflection is not needed as modelMapper is final, but we can set via constructor if needed - } - - @Test - void getByBenId_returnsNull() throws Exception { - String result = tbScreeningService.getByBenId(1L, "auth"); - assertNull(result); - } - - @Test - void save_newTBScreening_success() throws Exception { - TBScreeningDTO dto = new TBScreeningDTO(); - dto.setBenId(1L); - TBScreeningRequestDTO req = new TBScreeningRequestDTO(); - req.setUserId(10); - req.setTbScreeningList(Collections.singletonList(dto)); - when(tbScreeningRepo.getByUserIdAndBenId(1L, 10)).thenReturn(null); - when(tbScreeningRepo.save(any(TBScreening.class))).thenReturn(new TBScreening()); - String result = tbScreeningService.save(req); - assertTrue(result.contains("no of tb screening items saved: 1")); - } - - @Test - void save_existingTBScreening_success() throws Exception { - TBScreeningDTO dto = new TBScreeningDTO(); - dto.setBenId(2L); - TBScreeningRequestDTO req = new TBScreeningRequestDTO(); - req.setUserId(20); - req.setTbScreeningList(Collections.singletonList(dto)); - TBScreening existing = new TBScreening(); - existing.setId(99L); - when(tbScreeningRepo.getByUserIdAndBenId(2L, 20)).thenReturn(existing); - when(tbScreeningRepo.save(any(TBScreening.class))).thenReturn(existing); - String result = tbScreeningService.save(req); - assertTrue(result.contains("no of tb screening items saved: 1")); - } - - @Test - void save_exception() throws Exception { - TBScreeningDTO dto = new TBScreeningDTO(); - dto.setBenId(3L); - TBScreeningRequestDTO req = new TBScreeningRequestDTO(); - req.setUserId(30); - req.setTbScreeningList(Collections.singletonList(dto)); - when(tbScreeningRepo.getByUserIdAndBenId(3L, 30)).thenThrow(new RuntimeException("fail")); - assertThrows(Exception.class, () -> tbScreeningService.save(req)); - } - - @Test - void getByUserId_success() { - GetBenRequestHandler req = mock(GetBenRequestHandler.class); - Integer ashaId = 123; - Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); - Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); - when(req.getAshaId()).thenReturn(ashaId); - when(req.getFromDate()).thenReturn(fromDate); - when(req.getToDate()).thenReturn(toDate); - List tbList = Arrays.asList(new TBScreening(), new TBScreening()); - when(tbScreeningRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(tbList); - String json = tbScreeningService.getByUserId(req); - assertNotNull(json); - TBScreeningRequestDTO result = new Gson().fromJson(json, TBScreeningRequestDTO.class); - assertEquals(2, result.getTbScreeningList().size()); - assertEquals(ashaId, result.getUserId()); - } - - @Test - void getByUserId_emptyList() { - GetBenRequestHandler req = mock(GetBenRequestHandler.class); - Integer ashaId = 123; - Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); - Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); - when(req.getAshaId()).thenReturn(ashaId); - when(req.getFromDate()).thenReturn(fromDate); - when(req.getToDate()).thenReturn(toDate); - when(tbScreeningRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); - String json = tbScreeningService.getByUserId(req); - assertNotNull(json); - TBScreeningRequestDTO result = new Gson().fromJson(json, TBScreeningRequestDTO.class); - assertEquals(0, result.getTbScreeningList().size()); - assertEquals(ashaId, result.getUserId()); - } -} +//package com.iemr.flw.service.impl; +// +//import com.google.gson.Gson; +//import com.iemr.flw.domain.iemr.TBScreening; +//import com.iemr.flw.dto.identity.GetBenRequestHandler; +//import com.iemr.flw.dto.iemr.TBScreeningDTO; +//import com.iemr.flw.dto.iemr.TBScreeningRequestDTO; +//import com.iemr.flw.repo.iemr.TBScreeningRepo; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +//import org.junit.jupiter.api.extension.ExtendWith; +//import org.mockito.InjectMocks; +//import org.mockito.Mock; +//import org.mockito.junit.jupiter.MockitoExtension; +//import org.modelmapper.ModelMapper; +// +//import java.sql.Timestamp; +//import java.util.*; +// +//import static org.junit.jupiter.api.Assertions.*; +//import static org.mockito.ArgumentMatchers.*; +//import static org.mockito.Mockito.*; +// +//@ExtendWith(MockitoExtension.class) +//class TBScreeningServiceImplTest { +// @Mock +// private TBScreeningRepo tbScreeningRepo; +// @Mock +// private ModelMapper modelMapper; +// @InjectMocks +// private TBScreeningServiceImpl tbScreeningService; +// +// @BeforeEach +// void setUp() { +// // inject mock modelMapper +// // Reflection is not needed as modelMapper is final, but we can set via constructor if needed +// } +// +// @Test +// void getByBenId_returnsNull() throws Exception { +// String result = tbScreeningService.getByBenId(1L, "auth"); +// assertNull(result); +// } +// +// @Test +// void save_newTBScreening_success() throws Exception { +// TBScreeningDTO dto = new TBScreeningDTO(); +// dto.setBenId(1L); +// TBScreeningRequestDTO req = new TBScreeningRequestDTO(); +// req.setUserId(10); +// req.setTbScreeningList(Collections.singletonList(dto)); +// when(tbScreeningRepo.getByUserIdAndBenId(1L, 10)).thenReturn(null); +// when(tbScreeningRepo.save(any(TBScreening.class))).thenReturn(new TBScreening()); +// String result = tbScreeningService.save(req); +// assertTrue(result.contains("no of tb screening items saved: 1")); +// } +// +// @Test +// void save_existingTBScreening_success() throws Exception { +// TBScreeningDTO dto = new TBScreeningDTO(); +// dto.setBenId(2L); +// TBScreeningRequestDTO req = new TBScreeningRequestDTO(); +// req.setUserId(20); +// req.setTbScreeningList(Collections.singletonList(dto)); +// TBScreening existing = new TBScreening(); +// existing.setId(99L); +// when(tbScreeningRepo.getByUserIdAndBenId(2L, 20)).thenReturn(existing); +// when(tbScreeningRepo.save(any(TBScreening.class))).thenReturn(existing); +// String result = tbScreeningService.save(req); +// assertTrue(result.contains("no of tb screening items saved: 1")); +// } +// +// @Test +// void save_exception() throws Exception { +// TBScreeningDTO dto = new TBScreeningDTO(); +// dto.setBenId(3L); +// TBScreeningRequestDTO req = new TBScreeningRequestDTO(); +// req.setUserId(30); +// req.setTbScreeningList(Collections.singletonList(dto)); +// when(tbScreeningRepo.getByUserIdAndBenId(3L, 30)).thenThrow(new RuntimeException("fail")); +// assertThrows(Exception.class, () -> tbScreeningService.save(req)); +// } +// +// @Test +// void getByUserId_success() { +// GetBenRequestHandler req = mock(GetBenRequestHandler.class); +// Integer ashaId = 123; +// Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); +// Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); +// when(req.getAshaId()).thenReturn(ashaId); +// when(req.getFromDate()).thenReturn(fromDate); +// when(req.getToDate()).thenReturn(toDate); +// List tbList = Arrays.asList(new TBScreening(), new TBScreening()); +// when(tbScreeningRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(tbList); +// String json = tbScreeningService.getByUserId(req); +// assertNotNull(json); +// TBScreeningRequestDTO result = new Gson().fromJson(json, TBScreeningRequestDTO.class); +// assertEquals(2, result.getTbScreeningList().size()); +// assertEquals(ashaId, result.getUserId()); +// } +// +// @Test +// void getByUserId_emptyList() { +// GetBenRequestHandler req = mock(GetBenRequestHandler.class); +// Integer ashaId = 123; +// Timestamp fromDate = Timestamp.valueOf("2023-01-01 00:00:00"); +// Timestamp toDate = Timestamp.valueOf("2023-12-31 00:00:00"); +// when(req.getAshaId()).thenReturn(ashaId); +// when(req.getFromDate()).thenReturn(fromDate); +// when(req.getToDate()).thenReturn(toDate); +// when(tbScreeningRepo.getByUserId(ashaId, fromDate, toDate)).thenReturn(Collections.emptyList()); +// String json = tbScreeningService.getByUserId(req); +// assertNotNull(json); +// TBScreeningRequestDTO result = new Gson().fromJson(json, TBScreeningRequestDTO.class); +// assertEquals(0, result.getTbScreeningList().size()); +// assertEquals(ashaId, result.getUserId()); +// } +//} From e71d47076e8007b439b333804504c70d5c64edb7 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 12:55:55 +0530 Subject: [PATCH 154/237] adolescentHealth issue fix --- .../iemr/flw/controller/AdolescentHealthController.java | 7 ++----- .../iemr/flw/service/impl/AdolescentHealthServiceImpl.java | 2 ++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/AdolescentHealthController.java b/src/main/java/com/iemr/flw/controller/AdolescentHealthController.java index 11cc5e577..c72360fae 100644 --- a/src/main/java/com/iemr/flw/controller/AdolescentHealthController.java +++ b/src/main/java/com/iemr/flw/controller/AdolescentHealthController.java @@ -8,10 +8,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.List; @@ -27,7 +24,7 @@ public class AdolescentHealthController { private AdolescentHealthService adolescentHealthService; @RequestMapping(value = "/saveAll", method = RequestMethod.POST, headers = "Authorization") - public ResponseEntity> saveAdolescentHealth(@RequestBody AdolescentHealthDTO adolescentHealthDTO) { + public ResponseEntity> saveAdolescentHealth(@RequestBody AdolescentHealthDTO adolescentHealthDTO,@RequestHeader(value = "JwtToken") String token) { Map response = new HashMap<>(); try { diff --git a/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java index 8be992afe..9be73f7c5 100644 --- a/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java @@ -48,9 +48,11 @@ public String saveAll(AdolescentHealthDTO adolescentHealthDTO) { if (existingRecord.isPresent()) { // If record exists, update the existing one + adolescentHealth.setUserId(adolescentHealthDTO.getUserId()); updateAdolescentHealth(existingRecord, adolescentHealth); } else { // If the record does not exist, create a new one + adolescentHealth.setUserId(adolescentHealthDTO.getUserId()); adolescentHealthRepo.save(adolescentHealth); checkAndAddIncentives(adolescentHealth); } From 171dfea1e0053489e44e0be40f141e0bc5fbae1b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 13:43:00 +0530 Subject: [PATCH 155/237] adolescentHealth issue fix --- .../AdolescentHealthController.java | 53 ++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/AdolescentHealthController.java b/src/main/java/com/iemr/flw/controller/AdolescentHealthController.java index c72360fae..3b7dfe9ae 100644 --- a/src/main/java/com/iemr/flw/controller/AdolescentHealthController.java +++ b/src/main/java/com/iemr/flw/controller/AdolescentHealthController.java @@ -1,5 +1,6 @@ package com.iemr.flw.controller; +import com.google.gson.Gson; import com.iemr.flw.domain.iemr.AdolescentHealth; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.AdolescentHealthDTO; @@ -49,25 +50,61 @@ public ResponseEntity> saveAdolescentHealth(@RequestBody Ado } - @RequestMapping(value = "/getAll",method = RequestMethod.POST, headers = "Authorization") - public ResponseEntity> getAllAdolescentHealth(@RequestBody GetBenRequestHandler getBenRequestHandler) { - Map response = new HashMap<>(); + @RequestMapping( + value = "/getAll", + method = RequestMethod.POST, + headers = "Authorization" + ) + public ResponseEntity> getAllAdolescentHealth( + @RequestBody GetBenRequestHandler getBenRequestHandler) { + + Map response = new HashMap<>(); + long startTime = System.currentTimeMillis(); + logger.info("========================================"); + + logger.info("getAllAdolescentHealth API called"); + logger.info("========================================"); + try { - List resultList = adolescentHealthService.getAllAdolescentHealth(getBenRequestHandler); + + logger.info("getAllAdolescentHealth request: {}", + new Gson().toJson(getBenRequestHandler)); + + logger.debug("Fetching adolescent health records"); + + List resultList = + adolescentHealthService.getAllAdolescentHealth(getBenRequestHandler); + + int recordCount = resultList == null ? 0 : resultList.size(); + + logger.info( + "getAllAdolescentHealth: fetched {} records", + recordCount + ); if (resultList != null && !resultList.isEmpty()) { - response.put("statusCode",200); + response.put("statusCode", 200); response.put("data", resultList); } else { + logger.warn("getAllAdolescentHealth: no records returned"); + response.put("statusCode", 500); response.put("error", "Invalid/NULL request obj"); } } catch (Exception e) { - logger.error("Error in get data : " + e); - response.put("statusCode",500); - response.put("error","Error in get data : " + e); + // Logs the exception along with its full stack trace. + logger.error("getAllAdolescentHealth: failed to fetch records", e); + response.put("statusCode", 500); + response.put("error", "Unable to fetch adolescent health records"); + } finally { + logger.info( + "getAllAdolescentHealth completed: statusCode={}, durationMs={}", + response.get("statusCode"), + System.currentTimeMillis() - startTime + ); } + return ResponseEntity.ok(response); } } From 474980af53a1ad1a246acc27cd37ed1a13d9d284 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 15:36:24 +0530 Subject: [PATCH 156/237] adolescentHealth issue fix --- .../java/com/iemr/flw/service/impl/ChildCareServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 6660b9b06..4ee8e7a61 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -395,7 +395,9 @@ public List getChildVaccinationDetails(GetBenRequestHandler List benIdRows = beneficiaryRepo.getBenIdsFromRegIds(regIds); for (Object[] row : benIdRows) { Long regId = ((Number) row[0]).longValue(); - BigInteger benId = (BigInteger) row[1]; + BigInteger benId = row[1] == null + ? null + : new BigInteger(row[1].toString()); regIdToBenIdMap.put(regId, benId); } } From a07fdf2feaead68349aaccaa0957fafee4b313c6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 16:38:54 +0530 Subject: [PATCH 157/237] adolescentHealth issue fix --- .../impl/MaternalHealthServiceImpl.java | 124 +++++++++++++----- 1 file changed, 94 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 81eeb4ec8..313e3af78 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -451,13 +451,13 @@ public String saveANCVisitQuestions( List dtos, String authorization) throws IEMRException { - Integer userId = jwtUtil.extractUserId(authorization); - String userName = userRepo.getUserNamedByUserId(userId); - if (dtos == null || dtos.isEmpty()) { throw new IllegalArgumentException("ANC visit data is mandatory"); } + Integer userId = jwtUtil.extractUserId(authorization); + String userName = userRepo.getUserNamedByUserId(userId); + DateTimeFormatter formatter = DateTimeFormatter .ofPattern("dd-MM-uuuu") .withResolverStyle(java.time.format.ResolverStyle.STRICT); @@ -467,7 +467,25 @@ public String saveANCVisitQuestions( for (AncCounsellingCareDTO dto : dtos) { if (dto == null) { - throw new IllegalArgumentException("ANC visit record cannot be null"); + throw new IllegalArgumentException( + "ANC visit record cannot be null"); + } + + logger.info( + "ANC counselling DTO received: id={}, visitDate={}", + dto.getId(), + dto.getVisitDate() + ); + + if (dto.getId() != null && dto.getId() < 0) { + throw new IllegalArgumentException( + "id must be zero, null, or a positive existing record ID"); + } + + if (dto.getBeneficiaryId() == null + || dto.getBeneficiaryId() <= 0) { + throw new IllegalArgumentException( + "Valid beneficiaryId is mandatory"); } if (!StringUtils.hasText(dto.getVisitDate())) { @@ -475,71 +493,117 @@ public String saveANCVisitQuestions( } AncCounsellingCareListDTO fields = dto.getFields(); + if (fields == null) { throw new IllegalArgumentException("fields object is mandatory"); } LocalDate visitDate; try { - visitDate = LocalDate.parse(dto.getVisitDate(), formatter); + visitDate = LocalDate.parse( + dto.getVisitDate().trim(), formatter); } catch (DateTimeParseException e) { throw new IllegalArgumentException( - "Invalid visitDate, expected dd-MM-yyyy"); + "Invalid visitDate, expected dd-MM-yyyy", e); } LocalDate homeVisitDate; try { homeVisitDate = StringUtils.hasText(fields.getHomeVisitDate()) - ? LocalDate.parse(fields.getHomeVisitDate(), formatter) + ? LocalDate.parse( + fields.getHomeVisitDate().trim(), formatter) : visitDate; } catch (DateTimeParseException e) { throw new IllegalArgumentException( - "Invalid home_visit_date, expected dd-MM-yyyy"); + "Invalid home_visit_date, expected dd-MM-yyyy", e); } AncCounsellingCare entity; if (dto.getId() != null && dto.getId() > 0) { - // Update existing record + + // Existing ID: update only. Never create if this ID is missing. entity = ancCounsellingCareRepo.findById(dto.getId()) .orElseThrow(() -> new IllegalArgumentException( - "ANC visit not found for id: " + dto.getId())); + "ANC counselling record not found for id: " + + dto.getId())); + + // Prevent updating a different beneficiary's record. + if (!dto.getBeneficiaryId().equals(entity.getBeneficiaryId())) { + throw new IllegalArgumentException( + "beneficiaryId does not match ANC counselling record: " + + dto.getId()); + } + + logger.info( + "Updating ANC counselling record: id={}", + entity.getId() + ); + } else { - // Create new record + entity = new AncCounsellingCare(); entity.setBeneficiaryId(dto.getBeneficiaryId()); entity.setUserId(userId); entity.setCreatedBy(userName); + + logger.info( + "Creating ANC counselling record: requestId={}", + dto.getId() + ); + } + + if (entity.getAncVisitId() == null) { + entity.setAncVisitId(0L); } entity.setVisitDate(visitDate); entity.setHomeVisitDate(homeVisitDate); - entity.setSelectAll(yesNoToBoolean(fields.getSelectAll())); - entity.setSwelling(yesNoToBoolean(fields.getSwelling())); - entity.setHighBp(yesNoToBoolean(fields.getHighBp())); - entity.setConvulsions(yesNoToBoolean(fields.getConvulsions())); - entity.setAnemia(yesNoToBoolean(fields.getAnemia())); + entity.setSelectAll( + yesNoToBoolean(fields.getSelectAll())); + entity.setSwelling( + yesNoToBoolean(fields.getSwelling())); + entity.setHighBp( + yesNoToBoolean(fields.getHighBp())); + entity.setConvulsions( + yesNoToBoolean(fields.getConvulsions())); + entity.setAnemia( + yesNoToBoolean(fields.getAnemia())); entity.setReducedFetalMovement( yesNoToBoolean(fields.getReducedFetalMovement())); - entity.setAgeRisk(yesNoToBoolean(fields.getAgeRisk())); - entity.setChildGap(yesNoToBoolean(fields.getChildGap())); - entity.setShortHeight(yesNoToBoolean(fields.getShortHeight())); - entity.setPrePregWeight(yesNoToBoolean(fields.getPrePregWeight())); - entity.setBleeding(yesNoToBoolean(fields.getBleeding())); + entity.setAgeRisk( + yesNoToBoolean(fields.getAgeRisk())); + entity.setChildGap( + yesNoToBoolean(fields.getChildGap())); + entity.setShortHeight( + yesNoToBoolean(fields.getShortHeight())); + entity.setPrePregWeight( + yesNoToBoolean(fields.getPrePregWeight())); + entity.setBleeding( + yesNoToBoolean(fields.getBleeding())); entity.setMiscarriageHistory( yesNoToBoolean(fields.getMiscarriageHistory())); - entity.setFourPlusDelivery(yesNoToBoolean(fields.getFourPlusDelivery())); - entity.setFirstDelivery(yesNoToBoolean(fields.getFirstDelivery())); - entity.setTwinPregnancy(yesNoToBoolean(fields.getTwinPregnancy())); - entity.setCSectionHistory(yesNoToBoolean(fields.getCSectionHistory())); + entity.setFourPlusDelivery( + yesNoToBoolean(fields.getFourPlusDelivery())); + entity.setFirstDelivery( + yesNoToBoolean(fields.getFirstDelivery())); + entity.setTwinPregnancy( + yesNoToBoolean(fields.getTwinPregnancy())); + entity.setCSectionHistory( + yesNoToBoolean(fields.getCSectionHistory())); entity.setPreExistingDisease( yesNoToBoolean(fields.getPreExistingDisease())); - entity.setFeverMalaria(yesNoToBoolean(fields.getFeverMalaria())); - entity.setJaundice(yesNoToBoolean(fields.getJaundice())); - entity.setSickleCell(yesNoToBoolean(fields.getSickleCell())); - entity.setProlongedLabor(yesNoToBoolean(fields.getProlongedLabor())); - entity.setMalpresentation(yesNoToBoolean(fields.getMalpresentation())); + entity.setFeverMalaria( + yesNoToBoolean(fields.getFeverMalaria())); + entity.setJaundice( + yesNoToBoolean(fields.getJaundice())); + entity.setSickleCell( + yesNoToBoolean(fields.getSickleCell())); + entity.setProlongedLabor( + yesNoToBoolean(fields.getProlongedLabor())); + entity.setMalpresentation( + yesNoToBoolean(fields.getMalpresentation())); entity.setUpdatedBy(userName); entities.add(entity); From c0472931cda278f6ea2c67c114b8773f402b7b1c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 16:59:54 +0530 Subject: [PATCH 158/237] adolescentHealth issue fix --- .../dto/iemr/AncCounsellingCareListDTO.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java index 984425149..e21bea694 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java @@ -1,78 +1,94 @@ package com.iemr.flw.dto.iemr; +import com.fasterxml.jackson.annotation.JsonProperty; import com.google.gson.annotations.SerializedName; import lombok.Data; @Data public class AncCounsellingCareListDTO { + @JsonProperty("home_visit_date") @SerializedName("home_visit_date") private String homeVisitDate; + @JsonProperty("visit_number") + @SerializedName("visit_number") + private String visitNumber; + + @JsonProperty("select_all") @SerializedName("select_all") private String selectAll; - @SerializedName("swelling") private String swelling; + @JsonProperty("high_bp") @SerializedName("high_bp") private String highBp; - @SerializedName("convulsions") private String convulsions; - @SerializedName("anemia") private String anemia; + @JsonProperty("reduced_fetal_movement") @SerializedName("reduced_fetal_movement") private String reducedFetalMovement; + @JsonProperty("age_risk") @SerializedName("age_risk") private String ageRisk; + @JsonProperty("child_gap") @SerializedName("child_gap") private String childGap; + @JsonProperty("short_height") @SerializedName("short_height") private String shortHeight; + @JsonProperty("pre_preg_weight") @SerializedName("pre_preg_weight") private String prePregWeight; - @SerializedName("bleeding") private String bleeding; + @JsonProperty("miscarriage_history") @SerializedName("miscarriage_history") private String miscarriageHistory; + @JsonProperty("four_plus_delivery") @SerializedName("four_plus_delivery") private String fourPlusDelivery; + @JsonProperty("first_delivery") @SerializedName("first_delivery") private String firstDelivery; + @JsonProperty("twin_pregnancy") @SerializedName("twin_pregnancy") private String twinPregnancy; + @JsonProperty("c_section_history") @SerializedName("c_section_history") private String cSectionHistory; + @JsonProperty("pre_existing_disease") @SerializedName("pre_existing_disease") private String preExistingDisease; + @JsonProperty("fever_malaria") @SerializedName("fever_malaria") private String feverMalaria; - @SerializedName("jaundice") private String jaundice; + @JsonProperty("sickle_cell") @SerializedName("sickle_cell") private String sickleCell; + @JsonProperty("prolonged_labor") @SerializedName("prolonged_labor") private String prolongedLabor; - @SerializedName("malpresentation") private String malpresentation; From c1a43f0c964d0956d3a6b872e7853e415db9f425 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 17:00:36 +0530 Subject: [PATCH 159/237] adolescentHealth issue fix --- .../com/iemr/flw/service/impl/MaternalHealthServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 313e3af78..c4dab2c9b 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -678,7 +678,7 @@ private String booleanToYesNo(Boolean value) { private Boolean yesNoToBoolean(String value) { - return "Yes".equalsIgnoreCase(value); + return value != null && "Yes".equalsIgnoreCase(value.trim()); } From 0ff37068dd51d3ab8eb2dbda2f48e33e0e748099 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 17:46:45 +0530 Subject: [PATCH 160/237] add variable in common_example.properties --- .../environment/common_example.properties | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 3c679d09c..d85fa61a5 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -48,3 +48,52 @@ abha.xcmid= +# Diagnostic providers + +# Provider names: use the values supported by your application +diagnostic.provider.xray= +diagnostic.provider.truenat= + +# EMR Lite - Xray (base URL without trailing slash) +diagnostic.emrlite.xray.base-url=https:// +diagnostic.emrlite.xray.login-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/login/ +diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/getAccessToken/ +diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/ +diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/ +diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.xray.username= +diagnostic.emrlite.xray.password= + +# EMR Lite - Truenat +diagnostic.emrlite.truenat.base-url=https:// +diagnostic.emrlite.truenat.login-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/login/ +diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/getAccessToken/ +diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/ +diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/ +diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.truenat.username= +diagnostic.emrlite.truenat.password= + +# Token TTL: replace with vendor-configured durations in seconds +diagnostic.emrlite.refresh-ttl-seconds=86400 + +# Example: polling every 60 seconds +diagnostic.poll.xray.tick-ms=60000 +diagnostic.poll.truenat.tick-ms=60000 + +# Example: daily expiry at 11:59 PM in scheduler timezone +diagnostic.poll.expiry-cron=0 59 23 * * * + +# Local folder (Windows: use forward slashes) +diagnostic.documents.storage-root=C:/amrit/diagnostic-documents +stoptb.enforce.vanid=false +# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup +stoptb.van.id=0 + + + +# GovThealth API Config +govthealth.user.details.url=@env.GOVTHEALTH_USER_DETAILS_URL@ +govthealth.user.id=@env.GOVTHEALTH_USER_ID@ +govthealth.password=@env.GOVTHEALTH_PASSWORD@ +common-api-base-url= From 6335f0fc5b2896d1e623a55bb342e4f1b1c72382 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 22 Sep 2026 17:54:30 +0530 Subject: [PATCH 161/237] fix mda synch issue --- .../java/com/iemr/flw/domain/iemr/MdaDistributionData.java | 3 +++ .../iemr/flw/service/impl/MdaFormSubmissionServiceImpl.java | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/com/iemr/flw/domain/iemr/MdaDistributionData.java b/src/main/java/com/iemr/flw/domain/iemr/MdaDistributionData.java index 34c7a63e4..7985393a7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MdaDistributionData.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MdaDistributionData.java @@ -57,4 +57,7 @@ public class MdaDistributionData { @Column(name = "LastModDate") private Timestamp lastModDate; + + @Column(name = "AshaId") + private Integer ashaId; } diff --git a/src/main/java/com/iemr/flw/service/impl/MdaFormSubmissionServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MdaFormSubmissionServiceImpl.java index e7b0fe4eb..b25bfbab3 100644 --- a/src/main/java/com/iemr/flw/service/impl/MdaFormSubmissionServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MdaFormSubmissionServiceImpl.java @@ -6,6 +6,7 @@ import com.iemr.flw.dto.iemr.MdaFormSubmissionResponse; import com.iemr.flw.repo.iemr.MdaFormSubmissionRepository; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -24,6 +25,9 @@ public class MdaFormSubmissionServiceImpl implements MdaFormSubmissionService { @Autowired private final MdaFormSubmissionRepository repository; + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; + @Override public String saveFormData(List requests) { try { @@ -45,6 +49,7 @@ public String saveFormData(List requests) { .mdaDistributionDate(getMdaDistributionDate) .isMedicineDistributed(req.getFields().getIs_medicine_distributed()) .createdBy(req.getUserName()) + .ashaId(userServiceRoleRepo.getUserIdByName(req.getUserName())) .modifiedBy(req.getUserName()) .build(); entities.add(data); From a46784f1b8e1ae4f5def5135e05a4e25c777d962 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 28 Sep 2026 12:13:48 +0530 Subject: [PATCH 162/237] tb screen api changes --- .../com/iemr/flw/domain/iemr/TBScreening.java | 12 ++++ .../com/iemr/flw/dto/iemr/TBScreeningDTO.java | 63 ++++++++++++++++--- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java index 06e36309c..6867dd885 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java @@ -194,4 +194,16 @@ public class TBScreening { @Column(name = "createdDate") private java.sql.Timestamp createdDate; + + @Column(name = "risk_factor", columnDefinition = "TEXT") + private String riskFactor; + + @Column(name = "fatigue") + private Boolean fatigue; + + @Column(name = "chest_pain") + private Boolean chestPain; + + @Column(name = "short_breath") + private Boolean shortBreath; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java index 36f48dfc5..b27060a89 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java @@ -8,27 +8,20 @@ public class TBScreeningDTO { private Long id; - private Long benId; + private Long benRegId; + private Long visitCode; private Timestamp visitDate; private Boolean coughMoreThan2Weeks; - private Boolean bloodInSputum; - private Boolean feverMoreThan2Weeks; - private Boolean lossOfWeight; - private Boolean nightSweats; - private Boolean historyOfTb; - private Boolean takingAntiTBDrugs; - private Boolean familySufferingFromTB; - private Boolean riseOfFever; private Boolean lossOfAppetite; private Boolean age; @@ -37,7 +30,57 @@ public class TBScreeningDTO { private Boolean bmi; private Boolean contactWithTBPatient; private Boolean historyOfTBInLastFiveYrs; + + // Additional screening fields + private String riskFactor; + private Boolean hivStatus; + private Boolean fatigue; + private Boolean chestPain; + private Boolean shortBreath; + + // Screening option IDs + private Integer bloodCheckId; + private Integer coughCheckId; + private Integer familyCheckId; + private Integer feverCheckId; + private Integer historyCheckId; + private Integer weightCheckId; + private Integer sweatsCheckId; + private Integer drugsCheckId; + private Integer lossOfAppetiteId; + private Integer riseOfFeverId; + private String sympotomatic; private String asymptomatic; private String recommandateTest; -} + + // Recommended tests and referrals + private String recommendedForLiquidCulture; + private Integer recommendedForLiquidCultureId; + + private String recommendedForTruenat; + private Integer recommendedForTruenatId; + + private String referredForDigitalChestXray; + private Integer referredForDigitalChestXrayId; + + private String referredForSputumCollection; + private Integer referredForSputumCollectionId; + + private String sputumSampleSubmittedAt; + private String testDenialReasons; + + // Audit fields + private String createdBy; + private Timestamp createdDate; + private Boolean deleted; + private Timestamp lastModDate; + private String modifiedBy; + private String processed; + + // Service and location details + private Integer parkingPlaceID; + private Integer providerServiceMapId; + private Integer vanID; + private Long vanSerialNo; +} \ No newline at end of file From 59adb7dd031e28f46aa929dc6108a1b34440233a Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 28 Sep 2026 12:38:12 +0530 Subject: [PATCH 163/237] tb screen api changes --- .../com/iemr/flw/dto/iemr/TBScreeningDTO.java | 7 +- .../service/impl/TBScreeningServiceImpl.java | 153 +++++++++++++++--- 2 files changed, 139 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java index b27060a89..b81ca1c1f 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java @@ -3,6 +3,7 @@ import lombok.Data; import java.sql.Timestamp; +import java.util.List; @Data public class TBScreeningDTO { @@ -33,7 +34,6 @@ public class TBScreeningDTO { // Additional screening fields private String riskFactor; - private Boolean hivStatus; private Boolean fatigue; private Boolean chestPain; private Boolean shortBreath; @@ -83,4 +83,9 @@ public class TBScreeningDTO { private Integer providerServiceMapId; private Integer vanID; private Long vanSerialNo; + private Integer hivStatusId; + private String hivStatus; + private List keyPopulationRiskFactorIds; + private List keyPopulationRiskFactors; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java index 2f84c4622..5cff0bd0c 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java @@ -9,7 +9,9 @@ import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.TBScreeningRepo; import com.iemr.flw.service.TBScreeningService; +import jakarta.annotation.PostConstruct; import org.modelmapper.ModelMapper; +import org.modelmapper.TypeMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -17,7 +19,9 @@ import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; @Service public class TBScreeningServiceImpl implements TBScreeningService { @@ -36,37 +40,55 @@ public String getByBenId(Long benId, String authorisation) throws Exception { @Override public String save(TBScreeningRequestDTO requestDTO) throws Exception { - requestDTO.getTbScreeningList().forEach(tbScreeningDTO -> - { + if (requestDTO == null || requestDTO.getTbScreeningList() == null) { + throw new IllegalArgumentException("TB screening list is required"); + } + + for (TBScreeningDTO dto : requestDTO.getTbScreeningList()) { TBScreening tbScreening = - tbScreeningRepo.getByUserIdAndBenId(tbScreeningDTO.getBenId(), requestDTO.getUserId()); + tbScreeningRepo.getByUserIdAndBenId( + dto.getBenId(), requestDTO.getUserId()); boolean isNew = tbScreening == null; + if (isNew) { tbScreening = new TBScreening(); - modelMapper.map(tbScreeningDTO, tbScreening); - tbScreening.setId(null); - } else { - Long id = tbScreening.getId(); - modelMapper.map(tbScreeningDTO, tbScreening); - tbScreening.setId(id); } + modelMapper.map(dto, tbScreening); + + // List -> comma-separated String + tbScreening.setKeyPopulationRiskFactorIds( + toRiskFactorIdsCsv(dto.getKeyPopulationRiskFactorIds())); + + // List -> comma-separated String + tbScreening.setKeyPopulationRiskFactors( + toRiskFactorsCsv(dto.getKeyPopulationRiskFactors())); + tbScreening.setUserId(requestDTO.getUserId()); - // Stop TB / Nikshay reporting — same gap this ASHA-flow save path had as the nurse - // flow's saveNurseTBScreening(): benRegID was never persisted here at all. - tbScreening.setBenRegID(beneficiaryRepo.getRegIDFromBenId(tbScreeningDTO.getBenId())); - // created_date/created_by — gated on isNew so a later re-save doesn't overwrite the - // true creation time/author. No device-supplied created timestamp on this DTO, so - // visitDate (closest real proxy) is preferred, server time as last-resort fallback. + + tbScreening.setBenRegID( + beneficiaryRepo.getRegIDFromBenId(dto.getBenId())); + if (isNew) { - tbScreening.setCreatedDate(tbScreening.getVisitDate() != null - ? tbScreening.getVisitDate() : new Timestamp(System.currentTimeMillis())); - tbScreening.setCreatedBy(requestDTO.getUserId() != null ? requestDTO.getUserId().toString() : null); + tbScreening.setId(null); + + tbScreening.setCreatedDate( + tbScreening.getVisitDate() != null + ? tbScreening.getVisitDate() + : new Timestamp(System.currentTimeMillis())); + + tbScreening.setCreatedBy( + requestDTO.getUserId() != null + ? requestDTO.getUserId().toString() + : null); } + tbScreeningRepo.save(tbScreening); - }); - return "no of tb screening items saved: " + requestDTO.getTbScreeningList().size(); + } + + return "no of tb screening items saved: " + + requestDTO.getTbScreeningList().size(); } @Override @@ -88,4 +110,95 @@ public String getByUserId(GetBenRequestHandler request) { return null; } + @PostConstruct + public void configureTBScreeningMappings() { + TypeMap saveMapping = + modelMapper.getTypeMap(TBScreeningDTO.class, TBScreening.class); + + if (saveMapping == null) { + saveMapping = modelMapper.createTypeMap( + TBScreeningDTO.class, TBScreening.class); + } + + saveMapping.addMappings(mapper -> { + mapper.skip(TBScreening::setKeyPopulationRiskFactorIds); + mapper.skip(TBScreening::setKeyPopulationRiskFactors); + + // Managed by the service; preserve these on updates. + mapper.skip(TBScreening::setId); + mapper.skip(TBScreening::setCreatedDate); + mapper.skip(TBScreening::setCreatedBy); + }); + + TypeMap responseMapping = + modelMapper.getTypeMap(TBScreening.class, TBScreeningDTO.class); + + if (responseMapping == null) { + responseMapping = modelMapper.createTypeMap( + TBScreening.class, TBScreeningDTO.class); + } + + responseMapping.addMappings(mapper -> { + mapper.skip(TBScreeningDTO::setKeyPopulationRiskFactorIds); + mapper.skip(TBScreeningDTO::setKeyPopulationRiskFactors); + }); + } + + private String toRiskFactorIdsCsv(List ids) { + if (ids == null) { + return null; + } + + if (ids.stream().anyMatch(id -> id == null)) { + throw new IllegalArgumentException( + "Risk factor IDs cannot contain null values"); + } + + return ids.stream() + .map(String::valueOf) + .collect(Collectors.joining(",")); + } + + private String toRiskFactorsCsv(List riskFactors) { + if (riskFactors == null) { + return null; + } + + for (String riskFactor : riskFactors) { + if (riskFactor == null + || riskFactor.isBlank() + || riskFactor.contains(",")) { + throw new IllegalArgumentException( + "Risk factor codes cannot be null, blank, or contain commas"); + } + } + + return riskFactors.stream() + .map(String::trim) + .collect(Collectors.joining(",")); + } + + private List fromRiskFactorIdsCsv(String value) { + if (value == null || value.isBlank()) { + return new ArrayList<>(); + } + + return Arrays.stream(value.split(",")) + .map(String::trim) + .filter(item -> !item.isEmpty()) + .map(Integer::valueOf) + .collect(Collectors.toList()); + } + + private List fromRiskFactorsCsv(String value) { + if (value == null || value.isBlank()) { + return new ArrayList<>(); + } + + return Arrays.stream(value.split(",")) + .map(String::trim) + .filter(item -> !item.isEmpty()) + .collect(Collectors.toList()); + } + } From 5272ef774a6e135121e2edd8ced74b40911c8b66 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 28 Sep 2026 12:47:27 +0530 Subject: [PATCH 164/237] tb screen api changes --- .../service/impl/TBScreeningServiceImpl.java | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java index 5cff0bd0c..60ae88a40 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java @@ -95,19 +95,42 @@ public String save(TBScreeningRequestDTO requestDTO) throws Exception { public String getByUserId(GetBenRequestHandler request) { try { List dtos = new ArrayList<>(); - List tbScreeningList = tbScreeningRepo.getByUserId(request.getAshaId()); - tbScreeningList.forEach(tbScreening -> dtos.add(modelMapper.map(tbScreening, TBScreeningDTO.class))); - TBScreeningRequestDTO tbScreeningRequestDTO = new TBScreeningRequestDTO(); - tbScreeningRequestDTO.setTbScreeningList(dtos); - tbScreeningRequestDTO.setUserId(request.getAshaId()); + + List tbScreeningList = + tbScreeningRepo.getByUserId(request.getAshaId()); + + for (TBScreening tbScreening : tbScreeningList) { + TBScreeningDTO dto = + modelMapper.map(tbScreening, TBScreeningDTO.class); + + // Comma-separated String -> List + dto.setKeyPopulationRiskFactorIds( + fromRiskFactorIdsCsv( + tbScreening.getKeyPopulationRiskFactorIds())); + + // Comma-separated String -> List + dto.setKeyPopulationRiskFactors( + fromRiskFactorsCsv( + tbScreening.getKeyPopulationRiskFactors())); + + dtos.add(dto); + } + + TBScreeningRequestDTO response = new TBScreeningRequestDTO(); + response.setTbScreeningList(dtos); + response.setUserId(request.getAshaId()); + Gson gson = new GsonBuilder() - .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format + .setDateFormat("MMM dd, yyyy h:mm:ss a") .create(); - return gson.toJson(tbScreeningRequestDTO); - }catch (Exception e){ - logger.error("TBScreening Exception:"+e.getMessage()); + + return gson.toJson(response); + + } catch (Exception e) { + logger.error("Failed to retrieve TB screening details", e); + throw new IllegalStateException( + "Failed to retrieve TB screening details", e); } - return null; } @PostConstruct From a96c9888fd862130440225fbaa1b0f56c1accd8b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 28 Sep 2026 17:20:02 +0530 Subject: [PATCH 165/237] tb screen api changes --- .../com/iemr/flw/service/impl/TBScreeningServiceImpl.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java index 60ae88a40..adf3e0d1b 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java @@ -124,6 +124,13 @@ public String getByUserId(GetBenRequestHandler request) { .setDateFormat("MMM dd, yyyy h:mm:ss a") .create(); + + + String responseJson = gson.toJson(response); + + // Print complete response + logger.info("TB Screening COMPLETE RESPONSE: {}", responseJson); + return gson.toJson(response); } catch (Exception e) { From 6220f276e66aa2b0268b64df370d067d38227b68 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 29 Sep 2026 15:25:57 +0530 Subject: [PATCH 166/237] new api for tb referral follow up feature --- .../com/iemr/flw/controller/TBController.java | 67 ++++++++++ .../flw/domain/iemr/TbReferralFollowUp.java | 50 ++++++++ .../flw/dto/iemr/TBConfirmedRequestDTO.java | 1 + .../flw/dto/iemr/TbReferralFollowUpDTO.java | 13 ++ .../dto/iemr/TbReferralFollowUpListDTO.java | 14 ++ .../flw/repo/iemr/TbReferralFollowUpRepo.java | 15 +++ .../flw/service/TBConfirmedCaseService.java | 5 + .../impl/TBConfirmedCaseServiceImpl.java | 120 ++++++++++++++++-- 8 files changed, 275 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpListDTO.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/TbReferralFollowUpRepo.java diff --git a/src/main/java/com/iemr/flw/controller/TBController.java b/src/main/java/com/iemr/flw/controller/TBController.java index becc387a9..3d1abdefe 100644 --- a/src/main/java/com/iemr/flw/controller/TBController.java +++ b/src/main/java/com/iemr/flw/controller/TBController.java @@ -5,6 +5,7 @@ import com.iemr.flw.dto.iemr.TBConfirmedRequestDTO; import com.iemr.flw.dto.iemr.TBScreeningRequestDTO; import com.iemr.flw.dto.iemr.TBSuspectedRequestDTO; +import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; import com.iemr.flw.service.TBConfirmedCaseService; import com.iemr.flw.service.TBScreeningService; import com.iemr.flw.service.TBSuspectedService; @@ -192,6 +193,72 @@ public String getConfirmedByBenId( return response.toString(); } + @Operation(summary = "save tb referral follow up") + @RequestMapping(value = { "/referralFollowUp/save" }, method = { RequestMethod.POST }) + public String saveReferralFollowUp( + @RequestBody TbReferralFollowUpDTO requestDTO, + @RequestHeader(value = "jwtToken") String token) { + + OutputResponse response = new OutputResponse(); + + try { + if (requestDTO != null) { + + logger.info("request object with timestamp : " + + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + + String result = tbConfirmedCaseService.saveReferralFollowUp(requestDTO, token); + + if (result != null) + response.setResponse(result); + else + response.setError(500, "No record saved"); + + } else { + response.setError(500, "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in save tb referral follow up details : ", e); + response.setError(500, "Error in save referral follow up details : " + e.getMessage()); + } + + return response.toString(); + } + + + @Operation(summary = "save tb referral follow up") + @RequestMapping(value = { "/referralFollowUp/getAll" }, method = { RequestMethod.POST }) + public String getReferralFollowUp( + @RequestHeader(value = "jwtToken") String token) { + + OutputResponse response = new OutputResponse(); + + try { + if (token != null) { + + logger.info("request object with timestamp : " + + new Timestamp(System.currentTimeMillis()) + " " + + token); + + String result = tbConfirmedCaseService.getReferralFollowUp(token); + + if (result != null) + response.setResponse(result); + else + response.setError(500, "No record saved"); + + } else { + response.setError(500, "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in save tb referral follow up details : ", e); + response.setError(500, "Error in save referral follow up details : " + e.getMessage()); + } + + return response.toString(); + } + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java new file mode 100644 index 000000000..5adb2f88e --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java @@ -0,0 +1,50 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import org.checkerframework.checker.units.qual.C; + +import java.lang.reflect.Type; +import java.sql.Timestamp; + +@Data +@Table(schema = "tb_referral_follow_up") +public class TbReferralFollowUp { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "ben_id") + private Long benId; + + @Column(name = "household_id") + private Long houseHoldId; + + @Column(name = "referred_on_date") + private Timestamp referredOnDate; + + @Column(name = "follow_up_date") + private Timestamp followUpDate; + + @Column(name = "follow_up_status") + private String followUpStatus; + + @Column(name = "created_date") + private Timestamp createdDate; + + @Column(name = "created_date") + private Timestamp updatedDate; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "updated_by") + private String updatedBy; + + @Column(name = "synced_by") + private String syncedBy; + + @Column(name = "user_id") + private Integer userId; + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java index d3e76a4a7..9d3dab172 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java @@ -10,4 +10,5 @@ public class TBConfirmedRequestDTO { private Long userId; private List tbConfirmedList; + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpDTO.java new file mode 100644 index 000000000..ccd86e3e7 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpDTO.java @@ -0,0 +1,13 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class TbReferralFollowUpDTO { + private Long benId; + private Long houseHoldId; + TbReferralFollowUpListDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpListDTO.java new file mode 100644 index 000000000..a9f3e07ea --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpListDTO.java @@ -0,0 +1,14 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class TbReferralFollowUpListDTO { + @JsonProperty("referred_on_date") + private String referredOnDate; + @JsonProperty("follow_up_date") + private String followUpDate; + @JsonProperty("follow_up_status") + private String followUpStatus; +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/TbReferralFollowUpRepo.java b/src/main/java/com/iemr/flw/repo/iemr/TbReferralFollowUpRepo.java new file mode 100644 index 000000000..e41bb6b8f --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/TbReferralFollowUpRepo.java @@ -0,0 +1,15 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.TbReferralFollowUp; +import io.swagger.v3.oas.annotations.info.License; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import javax.swing.*; +import java.util.List; + +@Repository +public interface TbReferralFollowUpRepo extends JpaRepository { + List findByUserId(Integer userId); +} diff --git a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java index 6471f7996..36fbebffa 100644 --- a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java +++ b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java @@ -1,6 +1,7 @@ package com.iemr.flw.service; import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; +import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; import org.springframework.stereotype.Service; import java.util.List; @@ -15,4 +16,8 @@ public interface TBConfirmedCaseService { String getByUserId(String authorisation) throws Exception; String getByProviderServiceMapId(Integer providerServiceMapID, Integer villageID) throws Exception; + + String saveReferralFollowUp(TbReferralFollowUpDTO requestDTO, String token); + + String getReferralFollowUp(String token); } 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 836d853ac..a3ab25859 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -2,14 +2,13 @@ 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.BenVisitDetail; +import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; import com.iemr.flw.repo.identity.BeneficiaryRepo; 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.repo.iemr.TbReferralFollowUpRepo; import com.iemr.flw.seeder.TbCounsellingV2FormSeeder; import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.CampConfigService; @@ -25,12 +24,8 @@ import java.sql.Timestamp; import java.time.LocalDate; -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.time.format.DateTimeFormatter; +import java.util.*; import java.util.stream.Collectors; @Service @@ -57,6 +52,9 @@ public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { @Autowired private BeneficiaryRepo beneficiaryRepo; + @Autowired + private TbReferralFollowUpRepo tbReferralFollowUpRepo; + public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository, FormResponseRepo formResponseRepo, DynamicFormRepo dynamicFormRepo) { @@ -204,6 +202,108 @@ public String getByProviderServiceMapId(Integer providerServiceMapID, Integer vi return buildTbConfirmedCasesResponse(null, list); } + @Override + public String saveReferralFollowUp(TbReferralFollowUpDTO requestDTO, String token) { + OutputResponse response = new OutputResponse(); + + try { + + TbReferralFollowUp tbReferralFollowUp = new TbReferralFollowUp(); + + if(!token.isEmpty() && token!=null && requestDTO!=null){ + String userName = jwtUtil.extractUsername(token); + Integer userId = jwtUtil.extractUserId(token); + tbReferralFollowUp.setBenId(requestDTO.getBenId()); + tbReferralFollowUp.setHouseHoldId(requestDTO.getHouseHoldId()); + tbReferralFollowUp.setSyncedBy(userName); + tbReferralFollowUp.setCreatedBy(userName); + tbReferralFollowUp.setUserId(userId); + if(requestDTO.getFields().getReferredOnDate()!=null && !requestDTO.getFields().getFollowUpDate().isEmpty()){ + Timestamp referOnDate = Timestamp.valueOf(requestDTO.getFields().getReferredOnDate()); + tbReferralFollowUp.setFollowUpDate(referOnDate); + + } + + if(requestDTO.getFields().getFollowUpDate()!=null && !requestDTO.getFields().getFollowUpDate().isEmpty()){ + Timestamp followUpDate = Timestamp.valueOf(requestDTO.getFields().getFollowUpDate()); + tbReferralFollowUp.setFollowUpDate(followUpDate); + + } + tbReferralFollowUp.setFollowUpStatus(requestDTO.getFields().getFollowUpStatus()); + } + + tbReferralFollowUpRepo.save(tbReferralFollowUp); + response.setResponse("TB Referral follow up saved successfully"); + + + + }catch (Exception e){ + response.setError(500,e.getMessage()); + return response.toString(); + } + + + return response.toString(); + } + + @Override + public String getReferralFollowUp(String token) { + OutputResponse response = new OutputResponse(); + + try { + + List tbReferralFollowUpDTOS = new ArrayList<>(); + + if (token != null && !token.isEmpty()) { + + Integer userId = jwtUtil.extractUserId(token); + + List tbReferralFollowUps = + tbReferralFollowUpRepo.findByUserId(userId); + + DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + for (TbReferralFollowUp referral : tbReferralFollowUps) { + + TbReferralFollowUpDTO dto = new TbReferralFollowUpDTO(); + + dto.setBenId(referral.getBenId()); + dto.setHouseHoldId(referral.getHouseHoldId()); + + if (referral.getReferredOnDate() != null) { + dto.getFields().setReferredOnDate( + referral.getReferredOnDate() + .toLocalDateTime() + .format(formatter) + ); + } + + if (referral.getFollowUpDate() != null) { + dto.getFields().setFollowUpDate( + referral.getFollowUpDate() + .toLocalDateTime() + .format(formatter) + ); + } + + dto.getFields().setFollowUpStatus(referral.getFollowUpStatus()); + + tbReferralFollowUpDTOS.add(dto); + } + + response.setResponse(tbReferralFollowUpDTOS.toString()); + + } + + } catch (Exception e) { + response.setError(500,e.getMessage()); + return response.toString(); + } + + return response.toString(); + } + private String buildTbConfirmedCasesResponse(Integer userId, List list) { List dtoList = list.stream().map(this::toDTO).collect(Collectors.toList()); From cd1af6b7a3ba06e7f74df5335be222bd55abde87 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 29 Sep 2026 15:27:11 +0530 Subject: [PATCH 167/237] new api for tb referral follow up feature --- src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java index 5adb2f88e..bf204885c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java @@ -8,7 +8,7 @@ import java.sql.Timestamp; @Data -@Table(schema = "tb_referral_follow_up") +@Table(name = "tb_referral_follow_up",schema = "db_iemr") public class TbReferralFollowUp { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) From 4963ba8c4c56a7082e0d37e6ba793446756f9ba5 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 29 Sep 2026 15:30:38 +0530 Subject: [PATCH 168/237] new api for tb referral follow up feature --- .../flw/dto/iemr/TbReferralFollowUpDTO.java | 1 + .../impl/TBConfirmedCaseServiceImpl.java | 78 +++++++++++-------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpDTO.java index ccd86e3e7..a0a3bcee7 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TbReferralFollowUpDTO.java @@ -8,6 +8,7 @@ @Data public class TbReferralFollowUpDTO { private Long benId; + private Integer userId; private Long houseHoldId; TbReferralFollowUpListDTO fields; } 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 a3ab25859..7fbbfce87 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -1,9 +1,11 @@ package com.iemr.flw.service.impl; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; +import com.iemr.flw.dto.iemr.TbReferralFollowUpListDTO; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.DynamicFormRepo; import com.iemr.flw.repo.iemr.FormResponseRepo; @@ -251,54 +253,64 @@ public String getReferralFollowUp(String token) { OutputResponse response = new OutputResponse(); try { + if (token == null || token.trim().isEmpty()) { + response.setError(400, "Token is required"); + return response.toString(); + } - List tbReferralFollowUpDTOS = new ArrayList<>(); - - if (token != null && !token.isEmpty()) { - - Integer userId = jwtUtil.extractUserId(token); - - List tbReferralFollowUps = - tbReferralFollowUpRepo.findByUserId(userId); + Integer userId = jwtUtil.extractUserId(token); - DateTimeFormatter formatter = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + List referrals = + tbReferralFollowUpRepo.findByUserId(userId); - for (TbReferralFollowUp referral : tbReferralFollowUps) { + List referralDTOs = new ArrayList<>(); - TbReferralFollowUpDTO dto = new TbReferralFollowUpDTO(); + DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - dto.setBenId(referral.getBenId()); - dto.setHouseHoldId(referral.getHouseHoldId()); + for (TbReferralFollowUp referral : referrals) { - if (referral.getReferredOnDate() != null) { - dto.getFields().setReferredOnDate( - referral.getReferredOnDate() - .toLocalDateTime() - .format(formatter) - ); - } + TbReferralFollowUpDTO dto = new TbReferralFollowUpDTO(); + dto.setBenId(referral.getBenId()); + dto.setUserId(referral.getUserId()); + dto.setHouseHoldId(referral.getHouseHoldId()); - if (referral.getFollowUpDate() != null) { - dto.getFields().setFollowUpDate( - referral.getFollowUpDate() - .toLocalDateTime() - .format(formatter) - ); - } + // Initialize nested DTO before setting fields + TbReferralFollowUpListDTO fields = + new TbReferralFollowUpListDTO(); - dto.getFields().setFollowUpStatus(referral.getFollowUpStatus()); + if (referral.getReferredOnDate() != null) { + fields.setReferredOnDate( + referral.getReferredOnDate() + .toLocalDateTime() + .format(formatter) + ); + } - tbReferralFollowUpDTOS.add(dto); + if (referral.getFollowUpDate() != null) { + fields.setFollowUpDate( + referral.getFollowUpDate() + .toLocalDateTime() + .format(formatter) + ); } - response.setResponse(tbReferralFollowUpDTOS.toString()); + fields.setFollowUpStatus(referral.getFollowUpStatus()); + dto.setFields(fields); + referralDTOs.add(dto); } + ObjectMapper objectMapper = new ObjectMapper(); + + response.setResponse( + objectMapper.writeValueAsString(referralDTOs) + ); + } catch (Exception e) { - response.setError(500,e.getMessage()); - return response.toString(); + // Replace with your project's logger if available + e.printStackTrace(); + response.setError(500, "Failed to fetch referral follow-up: " + e.getMessage()); } return response.toString(); From 5db08538098d5cb08fe8722b0bf766155e13d003 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 29 Sep 2026 15:40:48 +0530 Subject: [PATCH 169/237] new api for tb referral follow up feature --- src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java index bf204885c..ecd78adb4 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java @@ -8,6 +8,7 @@ import java.sql.Timestamp; @Data +@Entity @Table(name = "tb_referral_follow_up",schema = "db_iemr") public class TbReferralFollowUp { @Id From 14a7cf7a470e8ac56c03ef157eec1e0ae9ce2a7e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 29 Sep 2026 15:45:44 +0530 Subject: [PATCH 170/237] new api for tb referral follow up feature --- src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java index ecd78adb4..6d642dbb8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java @@ -33,7 +33,7 @@ public class TbReferralFollowUp { @Column(name = "created_date") private Timestamp createdDate; - @Column(name = "created_date") + @Column(name = "updated_date") private Timestamp updatedDate; @Column(name = "created_by") From 5be34a83f8bc3cc920d15428188b24af9c39a762 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 29 Sep 2026 18:04:30 +0530 Subject: [PATCH 171/237] add sync date and sync by column in every table --- src/main/java/com/iemr/flw/domain/iemr/AHDForm.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java | 5 +++++ .../java/com/iemr/flw/domain/iemr/AdolescentHealth.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/AncCare.java | 4 ++++ .../com/iemr/flw/domain/iemr/AncCounsellingCare.java | 8 ++++++++ .../com/iemr/flw/domain/iemr/AshaSupervisorMapping.java | 9 +++++++++ src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java | 8 ++++++++ .../com/iemr/flw/domain/iemr/BenAnthropometryDetail.java | 2 ++ .../java/com/iemr/flw/domain/iemr/BenChiefComplaint.java | 1 + .../java/com/iemr/flw/domain/iemr/BenFlowStatus.java | 7 +++++++ .../com/iemr/flw/domain/iemr/BenPhysicalVitalDetail.java | 1 + .../java/com/iemr/flw/domain/iemr/BenReferDetails.java | 1 + src/main/java/com/iemr/flw/domain/iemr/CDR.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java | 8 ++++++++ .../java/com/iemr/flw/domain/iemr/CbacDetailsImer.java | 1 + .../java/com/iemr/flw/domain/iemr/ChildRegister.java | 7 +++++++ .../iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java | 9 +++++++++ .../java/com/iemr/flw/domain/iemr/DeliveryOutcome.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/DewormingForm.java | 7 +++++++ .../com/iemr/flw/domain/iemr/DiagnosticDocument.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/DiagnosticOrder.java | 7 +++++++ .../iemr/flw/domain/iemr/DiagnosticProviderToken.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/DiagnosticResult.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java | 1 + .../com/iemr/flw/domain/iemr/EligibleCoupleRegister.java | 7 +++++++ .../com/iemr/flw/domain/iemr/EligibleCoupleTracking.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/EyeCheckupVisit.java | 8 ++++++++ .../com/iemr/flw/domain/iemr/FilariasisCampaign.java | 8 ++++++++ src/main/java/com/iemr/flw/domain/iemr/FormResponse.java | 2 ++ src/main/java/com/iemr/flw/domain/iemr/FormSection.java | 1 + src/main/java/com/iemr/flw/domain/iemr/FormVersion.java | 1 + .../java/com/iemr/flw/domain/iemr/GeneralOpdData.java | 6 ++++++ .../java/com/iemr/flw/domain/iemr/GeneralOpdEntry.java | 9 +++++++++ src/main/java/com/iemr/flw/domain/iemr/HBYC.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/HbncPart1.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/HbncPart2.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/HbncVisitCard.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/HbycChildVisit.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/HighRiskAssess.java | 6 ++++++ .../com/iemr/flw/domain/iemr/IFAFormSubmissionData.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/IRSRound.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/IfaDistribution.java | 8 ++++++++ .../java/com/iemr/flw/domain/iemr/IncentiveActivity.java | 6 +++++- .../flw/domain/iemr/IncentiveActivityLangMapping.java | 5 +++++ .../iemr/flw/domain/iemr/IncentiveActivityRecord.java | 7 +++++++ .../iemr/flw/domain/iemr/IncentivePendingActivity.java | 8 ++++++++ .../java/com/iemr/flw/domain/iemr/InfantRegister.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/LeprosyFollowUp.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/MDSR.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/MalariaFollowUp.java | 7 +++++++ .../com/iemr/flw/domain/iemr/MdaDistributionData.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/MicroBirthPlan.java | 8 +++++++- .../java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java | 6 ++++++ .../flw/domain/iemr/NonPregnantWomanHighRiskAssess.java | 6 ++++++ .../flw/domain/iemr/NonPregnantWomanHighRiskTrack.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/Notification.java | 8 ++++++++ .../java/com/iemr/flw/domain/iemr/OptionCondition.java | 1 + .../java/com/iemr/flw/domain/iemr/OrsDistribution.java | 6 ++++++ .../java/com/iemr/flw/domain/iemr/OtpBeneficiary.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/PHCReviewForm.java | 6 ++++++ src/main/java/com/iemr/flw/domain/iemr/PMSMA.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/PNCVisit.java | 7 +++++++ .../com/iemr/flw/domain/iemr/PhyGeneralExamination.java | 1 + .../flw/domain/iemr/PregnantWomanHighRiskAssess.java | 7 +++++++ .../iemr/flw/domain/iemr/PregnantWomanHighRiskTrack.java | 6 ++++++ .../com/iemr/flw/domain/iemr/PregnantWomanRegister.java | 8 +++++++- .../com/iemr/flw/domain/iemr/PrescribedDrugDetail.java | 1 + .../com/iemr/flw/domain/iemr/PrescriptionDetail.java | 1 + .../com/iemr/flw/domain/iemr/PulsePolioCampaign.java | 6 ++++++ .../java/com/iemr/flw/domain/iemr/QuestionOption.java | 1 + .../java/com/iemr/flw/domain/iemr/QuestionResponse.java | 1 + .../com/iemr/flw/domain/iemr/QuestionValidation.java | 1 + src/main/java/com/iemr/flw/domain/iemr/SamVisit.java | 7 +++++++ .../com/iemr/flw/domain/iemr/SammelanAttachment.java | 8 ++++++++ .../java/com/iemr/flw/domain/iemr/SammelanRecord.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/ScreeningAesje.java | 8 ++++++++ .../com/iemr/flw/domain/iemr/ScreeningFilariasis.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java | 8 ++++++++ .../java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/ScreeningMalaria.java | 6 ++++++ .../java/com/iemr/flw/domain/iemr/SectionQuestion.java | 1 + .../java/com/iemr/flw/domain/iemr/SectionResponse.java | 1 + .../java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java | 7 +++++++ .../iemr/flw/domain/iemr/StopTBGeneralExamination.java | 7 +++++++ .../java/com/iemr/flw/domain/iemr/StopTBGeneralOpd.java | 7 +++++++ .../com/iemr/flw/domain/iemr/StopTBRegistration.java | 6 ++++++ .../java/com/iemr/flw/domain/iemr/TBConfirmedCase.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/TBScreening.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java | 7 +++++++ .../com/iemr/flw/domain/iemr/TbReferralFollowUp.java | 2 +- .../java/com/iemr/flw/domain/iemr/UserFcmTokenData.java | 9 ++++++++- src/main/java/com/iemr/flw/domain/iemr/UwinSession.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java | 6 ++++++ src/main/java/com/iemr/flw/domain/iemr/Vaccine.java | 7 +++++++ src/main/java/com/iemr/flw/domain/iemr/VhncForm.java | 7 +++++++ 97 files changed, 565 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/AHDForm.java b/src/main/java/com/iemr/flw/domain/iemr/AHDForm.java index a9a20dfb6..808ba7827 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AHDForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AHDForm.java @@ -44,4 +44,11 @@ public class AHDForm { @Column(name = "form_type") private String formType; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java b/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java index 4128f0826..c39047f73 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java @@ -173,7 +173,12 @@ public class ANCVisit { @Column(name = "place_of_ancId") private Integer placeOfAncId; + @Column(name = "synced_by") + private String syncedBy; + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/AdolescentHealth.java b/src/main/java/com/iemr/flw/domain/iemr/AdolescentHealth.java index 140087069..3aa0ac4b7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AdolescentHealth.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AdolescentHealth.java @@ -68,5 +68,12 @@ public class AdolescentHealth { @Column(name = "created_by") private String createdBy; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/AncCare.java b/src/main/java/com/iemr/flw/domain/iemr/AncCare.java index 6b1d5c752..63da1f0f2 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AncCare.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AncCare.java @@ -1,10 +1,13 @@ package com.iemr.flw.domain.iemr; import jakarta.persistence.*; +import lombok.Data; + import java.sql.Timestamp; import java.util.Objects; @Entity +@Data @Table(name = "t_anccare", schema = "db_iemr") public class AncCare { private long id; @@ -41,6 +44,7 @@ public class AncCare { private Timestamp syncedDate; private String reservedForChange; + @Id @Column(name = "ID") public long getId() { diff --git a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java index 18a3f7ad4..e80fb13a5 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java @@ -3,6 +3,7 @@ import jakarta.persistence.*; import lombok.Data; +import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; @@ -112,6 +113,13 @@ public class AncCounsellingCare { @Column(name = "malpresentation") private Boolean malpresentation = false; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + /* ---------- Lifecycle Hooks ---------- */ @PrePersist diff --git a/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java b/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java index ee641db8b..1817d8dee 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java @@ -9,6 +9,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.sql.Timestamp; + @Entity @Table(name = "asha_supervisor_mapping") @Data @@ -31,4 +33,11 @@ public class AshaSupervisorMapping { @Column(name = "deleted", insertable = false, updatable = true) private Boolean deleted; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java b/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java index 2df2bf43c..0c3e3b928 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java @@ -4,6 +4,7 @@ import jakarta.validation.constraints.*; import lombok.*; +import java.sql.Timestamp; import java.time.LocalDate; @@ -109,4 +110,11 @@ public class AshaWorker { @Column(name = "supervisorMobile") private String supervisorMobile; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenAnthropometryDetail.java b/src/main/java/com/iemr/flw/domain/iemr/BenAnthropometryDetail.java index 777e80118..f4e23e6d8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/BenAnthropometryDetail.java +++ b/src/main/java/com/iemr/flw/domain/iemr/BenAnthropometryDetail.java @@ -65,6 +65,8 @@ public class BenAnthropometryDetail { @Column(name = "SyncedBy") private String syncedBy; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenChiefComplaint.java b/src/main/java/com/iemr/flw/domain/iemr/BenChiefComplaint.java index 3b016c5fc..964f73c3c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/BenChiefComplaint.java +++ b/src/main/java/com/iemr/flw/domain/iemr/BenChiefComplaint.java @@ -68,6 +68,7 @@ public class BenChiefComplaint { @Column(name = "SyncedBy") private String syncedBy; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenFlowStatus.java b/src/main/java/com/iemr/flw/domain/iemr/BenFlowStatus.java index b4600e265..3451414a7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/BenFlowStatus.java +++ b/src/main/java/com/iemr/flw/domain/iemr/BenFlowStatus.java @@ -79,4 +79,11 @@ public class BenFlowStatus { @Column(name = "deleted", insertable = false) private Boolean deleted; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenPhysicalVitalDetail.java b/src/main/java/com/iemr/flw/domain/iemr/BenPhysicalVitalDetail.java index 15b03aee4..328877a01 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/BenPhysicalVitalDetail.java +++ b/src/main/java/com/iemr/flw/domain/iemr/BenPhysicalVitalDetail.java @@ -71,6 +71,7 @@ public class BenPhysicalVitalDetail { @Column(name = "SyncedBy") private String syncedBy; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenReferDetails.java b/src/main/java/com/iemr/flw/domain/iemr/BenReferDetails.java index 2112f3110..061aa9d9f 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/BenReferDetails.java +++ b/src/main/java/com/iemr/flw/domain/iemr/BenReferDetails.java @@ -126,6 +126,7 @@ public class BenReferDetails { private String syncedBy; @Expose + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/CDR.java b/src/main/java/com/iemr/flw/domain/iemr/CDR.java index 89744928c..e3e028dee 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/CDR.java +++ b/src/main/java/com/iemr/flw/domain/iemr/CDR.java @@ -93,4 +93,11 @@ public class CDR { @Column(name = "updated_by") private String updatedBy; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java b/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java index e33e15439..ec032f84a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java +++ b/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java @@ -3,6 +3,7 @@ import jakarta.persistence.*; import lombok.Data; +import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; @@ -42,6 +43,13 @@ public class CampaignOrs { @Column(name = "updated_date") private LocalDateTime updatedDate; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + /* ---------- Auto timestamps ---------- */ @PrePersist diff --git a/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java b/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java index 989ed1d1c..d46335ef9 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java +++ b/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java @@ -262,6 +262,7 @@ public class CbacDetailsImer { @Column(name = "SyncedBy") private String syncedBy; @Expose + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/ChildRegister.java b/src/main/java/com/iemr/flw/domain/iemr/ChildRegister.java index 4b4ca99aa..c4cbef8d4 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ChildRegister.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ChildRegister.java @@ -75,4 +75,11 @@ public class ChildRegister { @Column(name = "updated_by") private String updatedBy; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java b/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java index 10689cff3..f6b42581c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java @@ -2,6 +2,8 @@ import jakarta.persistence.*; import lombok.Data; + +import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; @@ -59,6 +61,13 @@ public class ChronicDiseaseVisitEntity { @Column(name = "updated_date") private LocalDateTime updatedDate; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + // 🔹 Auto timestamps @PrePersist protected void onCreate() { diff --git a/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java b/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java index d3a1b56ce..d6e6868b1 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java @@ -77,4 +77,11 @@ public class DeliveryOutcome { @Column(name = "updated_date") private Timestamp updatedDate; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/DewormingForm.java b/src/main/java/com/iemr/flw/domain/iemr/DewormingForm.java index 631dbfd51..1638e52e5 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DewormingForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DewormingForm.java @@ -47,4 +47,11 @@ public class DewormingForm { @Column(name = "form_type") private String formType; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticDocument.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticDocument.java index d4e78747f..508617747 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticDocument.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticDocument.java @@ -86,4 +86,11 @@ public class DiagnosticDocument { @Column(name = "vanSerialNo") private Long vanSerialNo; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java index 197999fe2..e9369e76f 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java @@ -103,4 +103,11 @@ public class DiagnosticOrder { @Column(name = "vanSerialNo") private Long vanSerialNo; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticProviderToken.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticProviderToken.java index 8ef233060..6ee5ea126 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticProviderToken.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticProviderToken.java @@ -48,4 +48,11 @@ public class DiagnosticProviderToken { @Column(name = "vanSerialNo") private Long vanSerialNo; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticResult.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticResult.java index 6cb9fba6b..734e98e98 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticResult.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticResult.java @@ -72,4 +72,11 @@ public class DiagnosticResult { @Column(name = "vanSerialNo") private Long vanSerialNo; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } 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 af183d66c..1c9a30530 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java @@ -106,6 +106,7 @@ public class DynamicForm { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/EligibleCoupleRegister.java b/src/main/java/com/iemr/flw/domain/iemr/EligibleCoupleRegister.java index 4a6226b44..b6299f903 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/EligibleCoupleRegister.java +++ b/src/main/java/com/iemr/flw/domain/iemr/EligibleCoupleRegister.java @@ -179,5 +179,12 @@ public class EligibleCoupleRegister { @Column(name = "kit_photo2", columnDefinition = "LONGTEXT") private String kitPhoto2; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/EligibleCoupleTracking.java b/src/main/java/com/iemr/flw/domain/iemr/EligibleCoupleTracking.java index 99b8b5115..929fc93bf 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/EligibleCoupleTracking.java +++ b/src/main/java/com/iemr/flw/domain/iemr/EligibleCoupleTracking.java @@ -72,4 +72,11 @@ public class EligibleCoupleTracking { @Column(name = "discharge_summary2") private String dischargeSummary2; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/EyeCheckupVisit.java b/src/main/java/com/iemr/flw/domain/iemr/EyeCheckupVisit.java index c15e84101..945fdeb48 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/EyeCheckupVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/EyeCheckupVisit.java @@ -3,6 +3,7 @@ import jakarta.persistence.*; import lombok.Data; +import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; @Data @@ -51,4 +52,11 @@ public class EyeCheckupVisit { @Column(name = "updated_date") private LocalDateTime updatedDate = LocalDateTime.now(); + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java b/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java index 2f0c12ad1..d2cd218a7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java @@ -3,6 +3,7 @@ import jakarta.persistence.*; import lombok.Data; +import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; @@ -49,6 +50,13 @@ public class FilariasisCampaign { @Column(name = "updated_date") private LocalDateTime updatedDate; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + /* ---------- Auto timestamps ---------- */ @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 8b338ee54..c6c160082 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java @@ -112,6 +112,7 @@ public class FormResponse { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; @@ -121,6 +122,7 @@ public class FormResponse { @Column(name = "SyncFailureReason") 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 28f50859b..b06ce48e7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java @@ -112,6 +112,7 @@ public class FormSection { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; 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 5902aa218..397fc22f6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java @@ -99,6 +99,7 @@ public class FormVersion { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/GeneralOpdData.java b/src/main/java/com/iemr/flw/domain/iemr/GeneralOpdData.java index f2d81f185..b2b0f2d02 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/GeneralOpdData.java +++ b/src/main/java/com/iemr/flw/domain/iemr/GeneralOpdData.java @@ -220,5 +220,11 @@ public class GeneralOpdData { @Column(name = "village") private String village; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/GeneralOpdEntry.java b/src/main/java/com/iemr/flw/domain/iemr/GeneralOpdEntry.java index 2e68c9fe9..9254dab88 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/GeneralOpdEntry.java +++ b/src/main/java/com/iemr/flw/domain/iemr/GeneralOpdEntry.java @@ -3,6 +3,8 @@ import jakarta.persistence.*; import lombok.Data; +import java.sql.Timestamp; + @Entity @Data @Table(name = "general_opd_entry") // Updated table name @@ -42,4 +44,11 @@ public class GeneralOpdEntry { @Column(name = "follow_up_date") private String followUpDate; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/HBYC.java b/src/main/java/com/iemr/flw/domain/iemr/HBYC.java index 2b5b1a08c..a52852a27 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HBYC.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HBYC.java @@ -102,4 +102,11 @@ public class HBYC { @Column(name = "updated_by") private String updatedBy; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/HbncPart1.java b/src/main/java/com/iemr/flw/domain/iemr/HbncPart1.java index f4ff6a5cd..02cb6736d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HbncPart1.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HbncPart1.java @@ -97,4 +97,11 @@ public class HbncPart1 { @Column(name = "updated_by") private String updatedBy; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/HbncPart2.java b/src/main/java/com/iemr/flw/domain/iemr/HbncPart2.java index b7828719f..7139086c5 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HbncPart2.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HbncPart2.java @@ -82,4 +82,11 @@ public class HbncPart2 { @Column(name = "updated_by") private String updatedBy; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java b/src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java index fa35c41e3..aa797a12c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HbncVisit.java @@ -110,4 +110,11 @@ public class HbncVisit { @Column(name = "is_admitted_in_sncu") private Boolean is_admitted_in_sncu; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; }; diff --git a/src/main/java/com/iemr/flw/domain/iemr/HbncVisitCard.java b/src/main/java/com/iemr/flw/domain/iemr/HbncVisitCard.java index 8008d07d5..c01d445f8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HbncVisitCard.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HbncVisitCard.java @@ -79,4 +79,11 @@ public class HbncVisitCard { @Column(name = "updated_by") private String updatedBy; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java b/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java index 205716cc9..03b92da4f 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java @@ -130,5 +130,12 @@ public class HbycChildVisit { @Column(name = "is_complementary_feeding") private Boolean complementary_feeding; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private java.sql.Timestamp syncedDate; + // Getters and Setters } diff --git a/src/main/java/com/iemr/flw/domain/iemr/HighRiskAssess.java b/src/main/java/com/iemr/flw/domain/iemr/HighRiskAssess.java index 4089e77c8..aac6f2df6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HighRiskAssess.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HighRiskAssess.java @@ -45,4 +45,10 @@ public class HighRiskAssess { @Column(name = "updated_by") private String updatedBy; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IFAFormSubmissionData.java b/src/main/java/com/iemr/flw/domain/iemr/IFAFormSubmissionData.java index 428269028..cf8e9e10d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IFAFormSubmissionData.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IFAFormSubmissionData.java @@ -62,4 +62,11 @@ public void onUpdate() { this.updatedAt = LocalDateTime.now(); } + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private java.sql.Timestamp syncedDate; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java b/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java index 6f3143e05..2574e26aa 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java @@ -7,6 +7,7 @@ import java.math.BigInteger; import java.sql.Date; +import java.sql.Timestamp; import java.time.LocalDate; @Entity @@ -34,4 +35,10 @@ public class IRSRound { @Column(name = "user_id") private Integer userId; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/IfaDistribution.java b/src/main/java/com/iemr/flw/domain/iemr/IfaDistribution.java index c6b613549..9cbe52062 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IfaDistribution.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IfaDistribution.java @@ -5,6 +5,7 @@ import lombok.Data; import org.checkerframework.checker.units.qual.C; +import java.sql.Timestamp; import java.time.LocalDate; @Entity @@ -39,4 +40,11 @@ public class IfaDistribution { @Column(name = "ifa_bottle_count") private String ifaBottleCount; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index 6402d9208..ce8ebc02e 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -66,6 +66,10 @@ public class IncentiveActivity { @Column(name = "group_category_name") private String groupCategoryName; + @Column(name = "synced_by") + private String syncedBy; - + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityLangMapping.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityLangMapping.java index 0c81338c1..f3ce1c2a7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityLangMapping.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityLangMapping.java @@ -43,5 +43,10 @@ public class IncentiveActivityLangMapping { @Column(name = "hindi_activity_description") private String hindiActivityDescription; + @Column(name = "synced_by") + private String syncedBy; + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java index 4a84055f0..c9b16da46 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java @@ -100,4 +100,11 @@ private void applyDefaults() { isApproved = false; } } + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java index 3f35dc599..b302b37b1 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java @@ -1,5 +1,6 @@ package com.iemr.flw.domain.iemr; +import java.sql.Timestamp; import java.util.Date; import jakarta.persistence.*; @@ -36,4 +37,11 @@ public class IncentivePendingActivity { @Column(name = "updated_date") private Date updatedDate; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java b/src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java index aee846efc..9c09c3472 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java +++ b/src/main/java/com/iemr/flw/domain/iemr/InfantRegister.java @@ -103,4 +103,11 @@ public class InfantRegister { @Column(name = "is_Referred_higher_facility") private Boolean isReferredHigherFacility; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/LeprosyFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/LeprosyFollowUp.java index 5e0d78f06..5decbe777 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/LeprosyFollowUp.java +++ b/src/main/java/com/iemr/flw/domain/iemr/LeprosyFollowUp.java @@ -87,4 +87,11 @@ public class LeprosyFollowUp { @Column(name = "last_mod_date") private Timestamp lastModDate; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/MDSR.java b/src/main/java/com/iemr/flw/domain/iemr/MDSR.java index 301fdd915..cace87f8c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MDSR.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MDSR.java @@ -63,4 +63,11 @@ public class MDSR { @Column(name = "mdsr_death_cert_file") private String mdsrDeathCertFile; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java b/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java index 0e8437141..3381d59d8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java @@ -54,4 +54,11 @@ public class MaaMeeting { @Column(name = "created_by") private String createdBy; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/MalariaFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/MalariaFollowUp.java index bc30e7dd4..115c371e8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MalariaFollowUp.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MalariaFollowUp.java @@ -56,4 +56,11 @@ public class MalariaFollowUp { @UpdateTimestamp @Column(name = "last_mod_date") private Timestamp lastModDate; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/MdaDistributionData.java b/src/main/java/com/iemr/flw/domain/iemr/MdaDistributionData.java index 7985393a7..b59164e3d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MdaDistributionData.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MdaDistributionData.java @@ -60,4 +60,11 @@ public class MdaDistributionData { @Column(name = "AshaId") private Integer ashaId; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/MicroBirthPlan.java b/src/main/java/com/iemr/flw/domain/iemr/MicroBirthPlan.java index 9b1458994..f5a89eccf 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MicroBirthPlan.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MicroBirthPlan.java @@ -66,4 +66,10 @@ public class MicroBirthPlan { private String modeOfTransportation; // Mode of transport -} \ No newline at end of file + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private java.sql.Timestamp syncedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java b/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java index 1f57d23ae..e75a3b0e6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java @@ -31,4 +31,10 @@ public class MosquitoNetEntity { @Column(name = "is_net_distributed") private String isNetDistributed; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private java.sql.Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/NonPregnantWomanHighRiskAssess.java b/src/main/java/com/iemr/flw/domain/iemr/NonPregnantWomanHighRiskAssess.java index 2b901a6d3..863358b6d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/NonPregnantWomanHighRiskAssess.java +++ b/src/main/java/com/iemr/flw/domain/iemr/NonPregnantWomanHighRiskAssess.java @@ -50,4 +50,10 @@ public class NonPregnantWomanHighRiskAssess { @Column(name = "visit_date") private Timestamp visitDate; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/NonPregnantWomanHighRiskTrack.java b/src/main/java/com/iemr/flw/domain/iemr/NonPregnantWomanHighRiskTrack.java index 6a3374d02..9f506a9cd 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/NonPregnantWomanHighRiskTrack.java +++ b/src/main/java/com/iemr/flw/domain/iemr/NonPregnantWomanHighRiskTrack.java @@ -77,4 +77,11 @@ public class NonPregnantWomanHighRiskTrack { @Column(name = "is_deleted") private Boolean isDeleted; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/Notification.java b/src/main/java/com/iemr/flw/domain/iemr/Notification.java index b2f4ba718..27da0402f 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/Notification.java +++ b/src/main/java/com/iemr/flw/domain/iemr/Notification.java @@ -64,4 +64,12 @@ protected void onCreate() { this.readDate = null; } } + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "synced_date") + private Date syncedDate; } \ No newline at end of file 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 50af2b382..975a23ad2 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java +++ b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java @@ -92,6 +92,7 @@ public class OptionCondition { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/OrsDistribution.java b/src/main/java/com/iemr/flw/domain/iemr/OrsDistribution.java index e5603deef..4e633303b 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/OrsDistribution.java +++ b/src/main/java/com/iemr/flw/domain/iemr/OrsDistribution.java @@ -39,4 +39,10 @@ public class OrsDistribution { @Column(name = "updated_at", insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") private java.sql.Timestamp updatedAt; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private java.sql.Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/OtpBeneficiary.java b/src/main/java/com/iemr/flw/domain/iemr/OtpBeneficiary.java index 15a87bd0e..be82820b8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/OtpBeneficiary.java +++ b/src/main/java/com/iemr/flw/domain/iemr/OtpBeneficiary.java @@ -30,4 +30,11 @@ public class OtpBeneficiary { @Column(name = "createdAt", updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") private Timestamp createdAt; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java b/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java index 4dea0ce7c..42665c94c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java @@ -57,4 +57,10 @@ public class PHCReviewForm { @Column(name = "form_type") private String formType; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/PMSMA.java b/src/main/java/com/iemr/flw/domain/iemr/PMSMA.java index f1320fee9..65b5c1607 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PMSMA.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PMSMA.java @@ -141,4 +141,11 @@ public class PMSMA { @Column(name = "anyOtherHighRiskCondition") private String anyOtherHighRiskCondition; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/PNCVisit.java b/src/main/java/com/iemr/flw/domain/iemr/PNCVisit.java index 04eb6f4a8..64bd2cbc8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PNCVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PNCVisit.java @@ -94,4 +94,11 @@ public class PNCVisit { @Column(name = "delivery_discharge_summary_image4") private String deliveryDischargeSummary4; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/PhyGeneralExamination.java b/src/main/java/com/iemr/flw/domain/iemr/PhyGeneralExamination.java index b99fd804b..466845c1d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PhyGeneralExamination.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PhyGeneralExamination.java @@ -74,6 +74,7 @@ public class PhyGeneralExamination { @Column(name = "SyncedBy") private String syncedBy; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanHighRiskAssess.java b/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanHighRiskAssess.java index 8e61655f4..b070ea61a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanHighRiskAssess.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanHighRiskAssess.java @@ -55,4 +55,11 @@ public class PregnantWomanHighRiskAssess { @Column(name = "is_high_risk") private Boolean isHighRisk; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanHighRiskTrack.java b/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanHighRiskTrack.java index 516cabfa1..f4c64623d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanHighRiskTrack.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanHighRiskTrack.java @@ -98,4 +98,10 @@ public class PregnantWomanHighRiskTrack { @Column(name = "is_deleted") private Boolean isDeleted; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanRegister.java b/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanRegister.java index 736f3afe3..9dba97dd7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanRegister.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PregnantWomanRegister.java @@ -116,5 +116,11 @@ public class PregnantWomanRegister { @Column(name = "updated_by") private String updatedBy; -} + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/PrescribedDrugDetail.java b/src/main/java/com/iemr/flw/domain/iemr/PrescribedDrugDetail.java index 9a0a1502c..bbf63f08c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PrescribedDrugDetail.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PrescribedDrugDetail.java @@ -77,6 +77,7 @@ public class PrescribedDrugDetail { @Column(name = "SyncedBy") private String syncedBy; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/PrescriptionDetail.java b/src/main/java/com/iemr/flw/domain/iemr/PrescriptionDetail.java index 5bc5295d6..a0dd33a29 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PrescriptionDetail.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PrescriptionDetail.java @@ -65,6 +65,7 @@ public class PrescriptionDetail { @Column(name = "SyncedBy") private String syncedBy; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java b/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java index ddf7b8b60..af0bd0914 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java @@ -3,6 +3,7 @@ import jakarta.persistence.*; import lombok.Data; +import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; @@ -56,5 +57,10 @@ protected void onUpdate() { this.updatedDate = LocalDateTime.now(); } + @Column(name = "synced_by") + private String syncedBy; + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } 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 124ea6faf..c732045a0 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java @@ -98,6 +98,7 @@ public class QuestionOption { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; 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 d743ad2dc..0c1821856 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java @@ -92,6 +92,7 @@ public class QuestionResponse { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; 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 b7d41dc16..300853c53 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java @@ -90,6 +90,7 @@ public class QuestionValidation { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/SamVisit.java b/src/main/java/com/iemr/flw/domain/iemr/SamVisit.java index 568226095..57957847d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SamVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SamVisit.java @@ -70,4 +70,11 @@ public class SamVisit { @Column(name = "updated_date") private LocalDateTime updatedDate = LocalDateTime.now(); + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private java.sql.Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/SammelanAttachment.java b/src/main/java/com/iemr/flw/domain/iemr/SammelanAttachment.java index e94dd2bc5..e98e84d10 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SammelanAttachment.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SammelanAttachment.java @@ -1,5 +1,6 @@ package com.iemr.flw.domain.iemr; +import java.sql.Timestamp; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; @@ -25,4 +26,11 @@ public class SammelanAttachment { private String fileType; @Lob private byte[] fileData; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/SammelanRecord.java b/src/main/java/com/iemr/flw/domain/iemr/SammelanRecord.java index 1ccc5bbd6..edef292e5 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SammelanRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SammelanRecord.java @@ -51,4 +51,11 @@ public class SammelanRecord { @Lob @Column(columnDefinition = "LONGTEXT",name = "attachments") private String attachments; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningAesje.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningAesje.java index 372908f99..2814c1e9e 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningAesje.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningAesje.java @@ -101,5 +101,13 @@ public class ScreeningAesje { @Column(name = "beneficiary_status_id") private Integer beneficiaryStatusId; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "synced_date") + private Date syncedDate; + // Getters and Setters } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningFilariasis.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningFilariasis.java index e75cb046c..79bcc3992 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningFilariasis.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningFilariasis.java @@ -83,4 +83,11 @@ public class ScreeningFilariasis { @Column(name = "user_id") private Integer userId; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "synced_date") + private Date syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java index d6bcd7b6c..5e62152f7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java @@ -108,4 +108,12 @@ public class ScreeningKalaAzar { @Column(name = "beneficiary_status") private String beneficiaryStatus; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "synced_date") + private Date syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java index 6a485eef7..22adb1f17 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java @@ -225,4 +225,11 @@ public class ScreeningLeprosy { @Column(name = "LastModDate") private Timestamp lastModDate; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningMalaria.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningMalaria.java index a310acb56..9d8ae1f3f 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningMalaria.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningMalaria.java @@ -139,5 +139,11 @@ public class ScreeningMalaria { @Column(name = "visit_date") private Date visitDate; + @Column(name = "synced_by") + private String syncedBy; + @org.hibernate.annotations.CreationTimestamp + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "synced_date") + private Date syncedDate; } \ No newline at end of file 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 1aa324cb5..67fc109f6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java @@ -124,6 +124,7 @@ public class SectionQuestion { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; 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 d8877a50c..b75ac79a6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java @@ -85,6 +85,7 @@ public class SectionResponse { @Column(name = "vanSerialNo") private Long vanSerialNo; + @org.hibernate.annotations.CreationTimestamp @Column(name = "SyncedDate") private Timestamp syncedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java b/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java index f9abde570..400074a06 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java +++ b/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java @@ -137,4 +137,11 @@ public class StopTBDiagnostics { @Column(name = "vanSerialNo") private Long vanSerialNo; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralExamination.java b/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralExamination.java index 9972d916d..6cfeaa28e 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralExamination.java +++ b/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralExamination.java @@ -130,4 +130,11 @@ public class StopTBGeneralExamination { @Column(name = "ben_id") private Long benId; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralOpd.java b/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralOpd.java index 4cfbb912a..a688b27d6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralOpd.java +++ b/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralOpd.java @@ -78,4 +78,11 @@ public class StopTBGeneralOpd { @Column(name = "benVisitID") private Long benVisitID; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/StopTBRegistration.java b/src/main/java/com/iemr/flw/domain/iemr/StopTBRegistration.java index 4ce54a0db..551a37370 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/StopTBRegistration.java +++ b/src/main/java/com/iemr/flw/domain/iemr/StopTBRegistration.java @@ -76,4 +76,10 @@ public class StopTBRegistration { @Column(name = "deleted") private Boolean deleted; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java index c2c51a6fb..23347cf98 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java @@ -102,4 +102,11 @@ public class TBConfirmedCase { @Column(name = "visitCode") private Long visitCode; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private java.sql.Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java index 6867dd885..c08f12775 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java @@ -206,4 +206,11 @@ public class TBScreening { @Column(name = "short_breath") private Boolean shortBreath; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java b/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java index 8aa015ec1..be27aaa57 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java @@ -122,4 +122,11 @@ public class TBSuspected { @Column(name = "visitCode") private Long visitCode; + + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java index 6d642dbb8..24e00774c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java @@ -48,4 +48,4 @@ public class TbReferralFollowUp { @Column(name = "user_id") private Integer userId; -} +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/UserFcmTokenData.java b/src/main/java/com/iemr/flw/domain/iemr/UserFcmTokenData.java index dd56c5b28..7005ba1e6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/UserFcmTokenData.java +++ b/src/main/java/com/iemr/flw/domain/iemr/UserFcmTokenData.java @@ -15,9 +15,16 @@ public class UserFcmTokenData { @GeneratedValue(strategy = IDENTITY) private int id; @Column(name = "user_id") - private Integer userId; + private Integer userId; @Column(name = "token") private String token; @Column(name = "updated_at") private Timestamp updatedAt; + @Column(name = "synced_by") + private String syncedBy; + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } + + diff --git a/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java b/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java index 9ab6d5cb3..f87ed3177 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java +++ b/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java @@ -39,5 +39,12 @@ public class UwinSession { @Column(name = "created_by") private String createdBy; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java b/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java index 758cc449a..2de5f6062 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java @@ -77,5 +77,11 @@ public class VHNDForm { @Column(name = "created_date", updatable = false) private Timestamp createdDate; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/Vaccine.java b/src/main/java/com/iemr/flw/domain/iemr/Vaccine.java index 0a03d259e..6975d7a8f 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/Vaccine.java +++ b/src/main/java/com/iemr/flw/domain/iemr/Vaccine.java @@ -70,4 +70,11 @@ public class Vaccine { @Column(name = "LastModDate") private Timestamp lastModDate; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java index 858554daf..f4370d79c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java @@ -66,4 +66,11 @@ public class VhncForm { @Column(name = "followup_previous") private Boolean followupPrevius; + @Column(name = "synced_by") + private String syncedBy; + + @org.hibernate.annotations.CreationTimestamp + @Column(name = "synced_date") + private Timestamp syncedDate; + } \ No newline at end of file From 1fc4688c2fb434f212286be62f8f8fd1e959928d Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 30 Sep 2026 18:08:55 +0530 Subject: [PATCH 172/237] new feature for tb tpt follow up --- .../com/iemr/flw/controller/TBController.java | 73 ++++- .../flw/domain/iemr/TbReferralFollowUp.java | 5 +- .../iemr/flw/domain/iemr/TbTptFollowUp.java | 82 ++++++ .../iemr/flw/dto/iemr/TbTptFollowUpDTO.java | 11 + .../flw/dto/iemr/TbTptFollowUpListDTO.java | 46 +++ .../iemr/flw/repo/iemr/TbTptFollowUpRepo.java | 13 + .../flw/service/TBConfirmedCaseService.java | 5 + .../impl/TBConfirmedCaseServiceImpl.java | 278 +++++++++++++++++- 8 files changed, 504 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/iemr/flw/domain/iemr/TbTptFollowUp.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpListDTO.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/TbTptFollowUpRepo.java diff --git a/src/main/java/com/iemr/flw/controller/TBController.java b/src/main/java/com/iemr/flw/controller/TBController.java index 3d1abdefe..214f0e54b 100644 --- a/src/main/java/com/iemr/flw/controller/TBController.java +++ b/src/main/java/com/iemr/flw/controller/TBController.java @@ -2,10 +2,7 @@ import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.TBConfirmedRequestDTO; -import com.iemr.flw.dto.iemr.TBScreeningRequestDTO; -import com.iemr.flw.dto.iemr.TBSuspectedRequestDTO; -import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; +import com.iemr.flw.dto.iemr.*; import com.iemr.flw.service.TBConfirmedCaseService; import com.iemr.flw.service.TBScreeningService; import com.iemr.flw.service.TBSuspectedService; @@ -261,4 +258,72 @@ public String getReferralFollowUp( + @Operation(summary = "save tb referral follow up") + @RequestMapping(value = { "/tptFollowUp/save" }, method = { RequestMethod.POST }) + public String savTptFollowUp( + @RequestBody TbTptFollowUpDTO requestDTO, + @RequestHeader(value = "jwtToken") String token) { + + OutputResponse response = new OutputResponse(); + + try { + if (requestDTO != null) { + + logger.info("request object with timestamp : " + + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + + String result = tbConfirmedCaseService.saveTptFollowUp(requestDTO, token); + + if (result != null) + response.setResponse(result); + else + response.setError(500, "No record saved"); + + } else { + response.setError(500, "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in save tb referral follow up details : ", e); + response.setError(500, "Error in save referral follow up details : " + e.getMessage()); + } + + return response.toString(); + } + + + @Operation(summary = "save tb referral follow up") + @RequestMapping(value = { "/tptFollowUp/getAll" }, method = { RequestMethod.POST }) + public String getTptFollowUp( + @RequestHeader(value = "jwtToken") String token) { + + OutputResponse response = new OutputResponse(); + + try { + if (token != null) { + + logger.info("request object with timestamp : " + + new Timestamp(System.currentTimeMillis()) + " " + + token); + + String result = tbConfirmedCaseService.getTptFollowUp(token); + + if (result != null) + response.setResponse(result); + else + response.setError(500, "No record saved"); + + } else { + response.setError(500, "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in save tb referral follow up details : ", e); + response.setError(500, "Error in save referral follow up details : " + e.getMessage()); + } + + return response.toString(); + } + + + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java index 24e00774c..206984dfc 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TbReferralFollowUp.java @@ -2,7 +2,8 @@ import jakarta.persistence.*; import lombok.Data; -import org.checkerframework.checker.units.qual.C; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; import java.lang.reflect.Type; import java.sql.Timestamp; @@ -30,9 +31,11 @@ public class TbReferralFollowUp { @Column(name = "follow_up_status") private String followUpStatus; + @CreationTimestamp @Column(name = "created_date") private Timestamp createdDate; + @UpdateTimestamp @Column(name = "updated_date") private Timestamp updatedDate; diff --git a/src/main/java/com/iemr/flw/domain/iemr/TbTptFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/TbTptFollowUp.java new file mode 100644 index 000000000..15900272c --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/TbTptFollowUp.java @@ -0,0 +1,82 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.sql.Timestamp; + +@Data +@Entity +@Table(name = "tb_tpt_follow_up",schema = "db_iemr") +public class TbTptFollowUp { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "ben_id") + private Long benId; + + @Column(name = "household_id") + private Long houseHoldId; + @Column(name = "regimen_type") + private String regimenType; + + @Column(name = "treatment_start_date") + private Timestamp treatmentStartDate; + + @Column(name = "expected_treatment_completion_date") + private Timestamp expectedTreatmentCompletionDate; + + @Column(name = "follow_up_date") + private Timestamp followUpDate; + + @Column(name = "follow_up_month") + private String followUpMonth; + + @Column(name = "adherence_to_medicines") + private String adherenceToMedicines; + + @Column(name = "any_discomfort") + private Boolean anyDiscomfort; + + @Column(name = "treatment_completed") + private Boolean treatmentCompleted; + + @Column(name = "actual_treatment_completion_date") + private Timestamp actualTreatmentCompletionDate; + + @Column(name = "tpt_outcome") + private String tptOutcome; + + @Column(name = "date_of_death") + private Timestamp dateOfDeath; + + @Column(name = "place_of_death") + private String placeOfDeath; + + @Column(name = "reason_for_death") + private String reasonForDeath; + + @CreationTimestamp + @Column(name = "created_date") + private Timestamp createdDate; + + @UpdateTimestamp + @Column(name = "updated_date") + private Timestamp updatedDate; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "updated_by") + private String updatedBy; + + @Column(name = "synced_by") + private String syncedBy; + + @Column(name = "user_id") + private Integer userId; + +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java new file mode 100644 index 000000000..8a0c2ca35 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java @@ -0,0 +1,11 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class TbTptFollowUpDTO { + private Long benId; + private Integer userId; + private Long houseHoldId; + TbTptFollowUpListDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpListDTO.java new file mode 100644 index 000000000..92b5cb026 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpListDTO.java @@ -0,0 +1,46 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class TbTptFollowUpListDTO { + @JsonProperty("regimen_type") + private String regimenType; + + @JsonProperty("treatment_start_date") + private String treatmentStartDate; + + @JsonProperty("expected_treatment_completion_date") + private String expectedTreatmentCompletionDate; + + @JsonProperty("follow_up_date") + private String followUpDate; + + @JsonProperty("monthly_follow_up") + private String monthlyFollowUp; + + @JsonProperty("medicine_adherence") + private String medicineAdherence; + + @JsonProperty("any_discomfort") + private String anyDiscomfort; + + @JsonProperty("treatment_completed") + private String treatmentCompleted; + + @JsonProperty("actual_completion_date") + private String actualCompletionDate; + + @JsonProperty("tpt_outcome") + private String tptOutcome; + + @JsonProperty("date_of_death") + private String dateOfDeath; + + @JsonProperty("place_of_death") + private String placeOfDeath; + + @JsonProperty("reason_for_death") + private String reasonForDeath; +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/TbTptFollowUpRepo.java b/src/main/java/com/iemr/flw/repo/iemr/TbTptFollowUpRepo.java new file mode 100644 index 000000000..f444d47a4 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/TbTptFollowUpRepo.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.TbReferralFollowUp; +import com.iemr.flw.domain.iemr.TbTptFollowUp; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface TbTptFollowUpRepo extends JpaRepository { + List findByUserId(Integer userId); +} diff --git a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java index 36fbebffa..23871f1b2 100644 --- a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java +++ b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java @@ -2,6 +2,7 @@ import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; +import com.iemr.flw.dto.iemr.TbTptFollowUpDTO; import org.springframework.stereotype.Service; import java.util.List; @@ -20,4 +21,8 @@ public interface TBConfirmedCaseService { String saveReferralFollowUp(TbReferralFollowUpDTO requestDTO, String token); String getReferralFollowUp(String token); + + String saveTptFollowUp(TbTptFollowUpDTO requestDTO, String token); + + String getTptFollowUp(String token); } 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 7fbbfce87..3f2125331 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -6,11 +6,10 @@ import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; import com.iemr.flw.dto.iemr.TbReferralFollowUpListDTO; +import com.iemr.flw.dto.iemr.TbTptFollowUpDTO; +import com.iemr.flw.dto.iemr.TbTptFollowUpListDTO; import com.iemr.flw.repo.identity.BeneficiaryRepo; -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.repo.iemr.TbReferralFollowUpRepo; +import com.iemr.flw.repo.iemr.*; import com.iemr.flw.seeder.TbCounsellingV2FormSeeder; import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.CampConfigService; @@ -57,6 +56,8 @@ public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { @Autowired private TbReferralFollowUpRepo tbReferralFollowUpRepo; + @Autowired + private TbTptFollowUpRepo tbTptFollowUpRepo; public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository, FormResponseRepo formResponseRepo, DynamicFormRepo dynamicFormRepo) { @@ -218,6 +219,7 @@ public String saveReferralFollowUp(TbReferralFollowUpDTO requestDTO, String toke tbReferralFollowUp.setBenId(requestDTO.getBenId()); tbReferralFollowUp.setHouseHoldId(requestDTO.getHouseHoldId()); tbReferralFollowUp.setSyncedBy(userName); + tbReferralFollowUp.setUpdatedBy(userName); tbReferralFollowUp.setCreatedBy(userName); tbReferralFollowUp.setUserId(userId); if(requestDTO.getFields().getReferredOnDate()!=null && !requestDTO.getFields().getFollowUpDate().isEmpty()){ @@ -316,6 +318,261 @@ public String getReferralFollowUp(String token) { return response.toString(); } + @Override + public String saveTptFollowUp(TbTptFollowUpDTO requestDTO, String token) { + + OutputResponse response = new OutputResponse(); + + try { + + TbTptFollowUp tbTptFollowUp = new TbTptFollowUp(); + + if (token != null && !token.isEmpty() && requestDTO != null) { + + String userName = jwtUtil.extractUsername(token); + Integer userId = jwtUtil.extractUserId(token); + + tbTptFollowUp.setBenId(requestDTO.getBenId()); + tbTptFollowUp.setUserId(userId); + + tbTptFollowUp.setCreatedBy(userName); + tbTptFollowUp.setUpdatedBy(userName); + + if (requestDTO.getFields() != null) { + + TbTptFollowUpListDTO fields = requestDTO.getFields(); + + tbTptFollowUp.setRegimenType(fields.getRegimenType()); + + if (fields.getTreatmentStartDate() != null + && !fields.getTreatmentStartDate().isEmpty()) { + + tbTptFollowUp.setTreatmentStartDate( + Timestamp.valueOf(fields.getTreatmentStartDate()) + ); + } + + if (fields.getExpectedTreatmentCompletionDate() != null + && !fields.getExpectedTreatmentCompletionDate().isEmpty()) { + + tbTptFollowUp.setExpectedTreatmentCompletionDate( + Timestamp.valueOf(fields.getExpectedTreatmentCompletionDate()) + ); + } + + if (fields.getFollowUpDate() != null + && !fields.getFollowUpDate().isEmpty()) { + + tbTptFollowUp.setFollowUpDate( + Timestamp.valueOf(fields.getFollowUpDate()) + ); + } + + tbTptFollowUp.setFollowUpMonth( + fields.getMonthlyFollowUp() + ); + + tbTptFollowUp.setAdherenceToMedicines( + fields.getMedicineAdherence() + ); + + tbTptFollowUp.setAnyDiscomfort( + convertBollen(fields.getAnyDiscomfort()) + ); + + tbTptFollowUp.setTreatmentCompleted( + convertBollen(fields.getTreatmentCompleted()) + ); + + if (fields.getActualCompletionDate() != null + && !fields.getActualCompletionDate().isEmpty()) { + + tbTptFollowUp.setActualTreatmentCompletionDate( + Timestamp.valueOf(fields.getActualCompletionDate()) + ); + } + + tbTptFollowUp.setTptOutcome( + fields.getTptOutcome() + ); + + if ("Death".equalsIgnoreCase(fields.getTptOutcome())) { + + if (fields.getDateOfDeath() != null + && !fields.getDateOfDeath().isEmpty()) { + + tbTptFollowUp.setDateOfDeath( + Timestamp.valueOf(fields.getDateOfDeath()) + ); + } + + tbTptFollowUp.setPlaceOfDeath( + fields.getPlaceOfDeath() + ); + + tbTptFollowUp.setReasonForDeath( + fields.getReasonForDeath() + ); + } + } + + tbTptFollowUpRepo.save(tbTptFollowUp); + } + + response.setResponse("TPT follow up saved successfully"); + + } catch (Exception e) { + + response.setError(500, e.getMessage()); + return response.toString(); + } + + return response.toString(); + } + + + @Override + public String getTptFollowUp(String token) { + + OutputResponse response = new OutputResponse(); + + try { + + if (token == null || token.trim().isEmpty()) { + response.setError(400, "Token is required"); + return response.toString(); + } + + Integer userId = jwtUtil.extractUserId(token); + + List tptFollowUps = + tbTptFollowUpRepo.findByUserId(userId); + + List tptFollowUpDTOs = + new ArrayList<>(); + + DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + for (TbTptFollowUp tptFollowUp : tptFollowUps) { + + TbTptFollowUpDTO dto = new TbTptFollowUpDTO(); + + dto.setBenId(tptFollowUp.getBenId()); + dto.setUserId(tptFollowUp.getUserId()); + + TbTptFollowUpListDTO fields = + new TbTptFollowUpListDTO(); + + // Regimen Type + fields.setRegimenType( + tptFollowUp.getRegimenType() + ); + + // Treatment Start Date + if (tptFollowUp.getTreatmentStartDate() != null) { + fields.setTreatmentStartDate( + tptFollowUp.getTreatmentStartDate() + .toLocalDateTime() + .format(formatter) + ); + } + + // Expected Treatment Completion Date + if (tptFollowUp.getExpectedTreatmentCompletionDate() != null) { + fields.setExpectedTreatmentCompletionDate( + tptFollowUp.getExpectedTreatmentCompletionDate() + .toLocalDateTime() + .format(formatter) + ); + } + + // Follow Up Date + if (tptFollowUp.getFollowUpDate() != null) { + fields.setFollowUpDate( + tptFollowUp.getFollowUpDate() + .toLocalDateTime() + .format(formatter) + ); + } + + // Monthly Follow Up + fields.setMonthlyFollowUp( + tptFollowUp.getFollowUpMonth() + ); + + // Medicine Adherence + fields.setMedicineAdherence( + tptFollowUp.getAdherenceToMedicines() + ); + + // Any Discomfort + fields.setAnyDiscomfort( + convert(tptFollowUp.getAnyDiscomfort()) + ); + + // Treatment Completed + fields.setTreatmentCompleted( + convert(tptFollowUp.getTreatmentCompleted()) + ); + + // Actual Completion Date + if (tptFollowUp.getActualTreatmentCompletionDate() != null) { + fields.setActualCompletionDate( + tptFollowUp.getActualTreatmentCompletionDate() + .toLocalDateTime() + .format(formatter) + ); + } + + // TPT Outcome + fields.setTptOutcome( + tptFollowUp.getTptOutcome() + ); + + // Date of Death + if (tptFollowUp.getDateOfDeath() != null) { + fields.setDateOfDeath( + tptFollowUp.getDateOfDeath() + .toLocalDateTime() + .format(formatter) + ); + } + + // Place of Death + fields.setPlaceOfDeath( + tptFollowUp.getPlaceOfDeath() + ); + + // Reason for Death + fields.setReasonForDeath( + tptFollowUp.getReasonForDeath() + ); + + dto.setFields(fields); + + tptFollowUpDTOs.add(dto); + } + + ObjectMapper objectMapper = new ObjectMapper(); + + response.setResponse( + objectMapper.writeValueAsString(tptFollowUpDTOs) + ); + + } catch (Exception e) { + + e.printStackTrace(); + + response.setError( + 500, + "Failed to fetch TPT follow-up: " + e.getMessage() + ); + } + + return response.toString(); + } + private String buildTbConfirmedCasesResponse(Integer userId, List list) { List dtoList = list.stream().map(this::toDTO).collect(Collectors.toList()); @@ -366,4 +623,17 @@ private TBConfirmedCaseDTO toDTO(TBConfirmedCase entity) { return dto; } + + private String convert(Boolean value) { + if (value == null) return null; + return value ? "Yes" : "No"; + } + + private Boolean convertBollen(String value) { + if (value != null && !value.isEmpty()) { + return value.equalsIgnoreCase("Yes"); + } else { + return false; + } + } } From 01d5c3f762ac0764c1e86084aae3b195fe723f5f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 30 Sep 2026 18:09:27 +0530 Subject: [PATCH 173/237] new feature for tb tpt follow up --- src/main/java/com/iemr/flw/controller/TBController.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/TBController.java b/src/main/java/com/iemr/flw/controller/TBController.java index 214f0e54b..6dae41132 100644 --- a/src/main/java/com/iemr/flw/controller/TBController.java +++ b/src/main/java/com/iemr/flw/controller/TBController.java @@ -258,7 +258,7 @@ public String getReferralFollowUp( - @Operation(summary = "save tb referral follow up") + @Operation(summary = "save tb tpt follow up") @RequestMapping(value = { "/tptFollowUp/save" }, method = { RequestMethod.POST }) public String savTptFollowUp( @RequestBody TbTptFollowUpDTO requestDTO, @@ -284,7 +284,7 @@ public String savTptFollowUp( response.setError(500, "Invalid/NULL request obj"); } } catch (Exception e) { - logger.error("Error in save tb referral follow up details : ", e); + logger.error("Error in save tb tpt follow up details : ", e); response.setError(500, "Error in save referral follow up details : " + e.getMessage()); } @@ -292,7 +292,7 @@ public String savTptFollowUp( } - @Operation(summary = "save tb referral follow up") + @Operation(summary = "save tb tpt follow up") @RequestMapping(value = { "/tptFollowUp/getAll" }, method = { RequestMethod.POST }) public String getTptFollowUp( @RequestHeader(value = "jwtToken") String token) { @@ -317,7 +317,7 @@ public String getTptFollowUp( response.setError(500, "Invalid/NULL request obj"); } } catch (Exception e) { - logger.error("Error in save tb referral follow up details : ", e); + logger.error("Error in save tb tpt follow up details : ", e); response.setError(500, "Error in save referral follow up details : " + e.getMessage()); } From 4c26b1f81a6eb19de7b321bab792d5724181772b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 30 Sep 2026 18:09:43 +0530 Subject: [PATCH 174/237] new feature for tb tpt follow up --- src/main/java/com/iemr/flw/controller/TBController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/TBController.java b/src/main/java/com/iemr/flw/controller/TBController.java index 6dae41132..9ec9f73a0 100644 --- a/src/main/java/com/iemr/flw/controller/TBController.java +++ b/src/main/java/com/iemr/flw/controller/TBController.java @@ -285,7 +285,7 @@ public String savTptFollowUp( } } catch (Exception e) { logger.error("Error in save tb tpt follow up details : ", e); - response.setError(500, "Error in save referral follow up details : " + e.getMessage()); + response.setError(500, "Error in save tpt follow up details : " + e.getMessage()); } return response.toString(); @@ -318,7 +318,7 @@ public String getTptFollowUp( } } catch (Exception e) { logger.error("Error in save tb tpt follow up details : ", e); - response.setError(500, "Error in save referral follow up details : " + e.getMessage()); + response.setError(500, "Error in save tpt follow up details : " + e.getMessage()); } return response.toString(); From 1fd54ab1e8d3b9f3f9c895f8c2658b028995fadf Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 30 Sep 2026 18:19:59 +0530 Subject: [PATCH 175/237] new feature for tb tpt follow up --- src/main/java/com/iemr/flw/domain/iemr/IRSRound.java | 2 +- .../com/iemr/flw/service/impl/IRSRoundServiceImpl.java | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java b/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java index 2574e26aa..c964765ee 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java @@ -40,5 +40,5 @@ public class IRSRound { @org.hibernate.annotations.CreationTimestamp @Column(name = "synced_date") - private Timestamp syncedDate; + private Timestamp syncedDate = null; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java index 26a5c1c74..5e8853a5b 100644 --- a/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -26,7 +27,7 @@ public List addRounds(List dtos,Integer userId,String use } return irsRoundRepository.saveAll( dtos.stream() - .map(dto -> new IRSRound(null, dto.getDate(), dto.getRounds(), dto.getHouseholdId(),userName,userId)) + .map(dto -> new IRSRound(null, dto.getDate(), dto.getRounds(), dto.getHouseholdId(),userName,userId ,userName,getCurrentTimestamp())) .collect(Collectors.toList()) ); } @@ -35,4 +36,8 @@ public List addRounds(List dtos,Integer userId,String use public List getRounds(Long householdId) { return irsRoundRepository.findByHouseholdId(householdId); } + + private Timestamp getCurrentTimestamp() { + return new Timestamp(System.currentTimeMillis()); + } } From 7c7d2eab7b968f2131e1de3dfd6f827d1427bbc2 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 30 Sep 2026 22:45:12 +0530 Subject: [PATCH 176/237] new feature for tb tpt follow up --- src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java index 8a0c2ca35..370da8eb6 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TbTptFollowUpDTO.java @@ -1,11 +1,15 @@ package com.iemr.flw.dto.iemr; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @Data public class TbTptFollowUpDTO { + @JsonProperty("ben_id") private Long benId; + @JsonProperty("user_id") private Integer userId; + @JsonProperty("house_hold_id") private Long houseHoldId; TbTptFollowUpListDTO fields; } From 537520b918056ea46ffd64830c4757e6003a9ec4 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 1 Oct 2026 15:02:14 +0530 Subject: [PATCH 177/237] new feature for tb tpt follow up --- .../flw/service/impl/DeliveryOutcomeServiceImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index 3170deba0..3881904b9 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -170,7 +170,15 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getDeliveryOutcome() == 1) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + + if(placeOfDelivery != null && + (!placeOfDelivery.equalsIgnoreCase("home") || + !placeOfDelivery.equalsIgnoreCase("in transit") || + !placeOfDelivery.equalsIgnoreCase("other private hospital"))){ + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); + + } } } } From d0f7bc419a663a5877ce8fecc0a9f4d5a4df20ef Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 1 Oct 2026 15:36:26 +0530 Subject: [PATCH 178/237] fix jsy incentive issue --- .../identity/RMNCHHouseHoldDetails.java | 8 ++++++ .../impl/DeliveryOutcomeServiceImpl.java | 28 ++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) 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 49f4d5a61..311abc7a6 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java @@ -353,4 +353,12 @@ public class RMNCHHouseHoldDetails { @Column(name = "registeredAtCampSiteId") private Integer registeredAtCampSiteId; + @Expose + @Column(name = "placeOfCurrentLiving") + private String placeOfCurrentLiving; + + @Expose + @Column(name = "nameOfInstitution") + private String nameOfInstitution; + } diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index 3881904b9..efa1d29fe 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -171,7 +171,6 @@ public void checkAndAddJsyIncentive(List delOutList) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); if (deliveryOutcome.getPlaceOfDelivery() != null) { String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); - if(placeOfDelivery != null && (!placeOfDelivery.equalsIgnoreCase("home") || !placeOfDelivery.equalsIgnoreCase("in transit") || @@ -189,8 +188,15 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getDeliveryOutcome() == 2) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY2); if (deliveryOutcome.getPlaceOfDelivery() != null) { + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + if(placeOfDelivery != null && + (!placeOfDelivery.equalsIgnoreCase("home") || + !placeOfDelivery.equalsIgnoreCase("in transit") || + !placeOfDelivery.equalsIgnoreCase("other private hospital"))){ + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); + + } - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); } } } @@ -200,7 +206,14 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getDeliveryOutcome() == 3) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY3); if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + if(placeOfDelivery != null && + (!placeOfDelivery.equalsIgnoreCase("home") || + !placeOfDelivery.equalsIgnoreCase("in transit") || + !placeOfDelivery.equalsIgnoreCase("other private hospital"))){ + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); + + } } } } @@ -210,7 +223,14 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getDeliveryOutcome() == 4) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY4); if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + if(placeOfDelivery != null && + (!placeOfDelivery.equalsIgnoreCase("home") || + !placeOfDelivery.equalsIgnoreCase("in transit") || + !placeOfDelivery.equalsIgnoreCase("other private hospital"))){ + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); + + } } } From 4f431752a04708329a32e25c4a5bdf58c4c4c5f4 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 1 Oct 2026 16:58:10 +0530 Subject: [PATCH 179/237] fix jsy incentive issue --- .../java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java | 1 + src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java b/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java index 415fd1b19..6d7a8a5d3 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java @@ -47,4 +47,5 @@ public class EligibleCoupleTrackingDTO implements Serializable { private String dischargeSummary1; private String dischargeSummary2; + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java b/src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java index d3cc280bf..50834c5a2 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/InfantRegisterDTO.java @@ -38,5 +38,7 @@ public class InfantRegisterDTO { private String deliveryDischargeSummary4; private String isSNCU; private Boolean isReferredHigherFacility; + private String syncedBy; + private Timestamp syncedDate; } From b5794a77e5c4857d0474f0abc935f54c886f532c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 1 Oct 2026 17:30:22 +0530 Subject: [PATCH 180/237] fix jsy incentive issue --- src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java | 3 +++ src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java index 5e94697a1..e54553884 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java @@ -1,6 +1,7 @@ package com.iemr.flw.dto.iemr; import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.Column; import lombok.Data; import java.sql.Timestamp; @@ -30,4 +31,6 @@ public class DeliveryOutcomeDTO { private String createdBy; private Timestamp updatedDate; private String updatedBy; + private String syncedBy; + private Timestamp syncedDate; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java index e2a6787c1..5e775d702 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java @@ -62,6 +62,8 @@ public class IncentiveRecordDTO { private String supervisorRole; private Boolean isApproved; + private String syncedBy; + private Timestamp syncedDate; From 52c6c4eb069eeb360dffab8a3acdf6d04cb505ba Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 1 Oct 2026 17:34:24 +0530 Subject: [PATCH 181/237] fix vhnc incentive issue --- src/main/java/com/iemr/flw/domain/iemr/VhncForm.java | 7 ------- .../flw/service/impl/DeliveryOutcomeServiceImpl.java | 10 +++++----- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java index f4370d79c..858554daf 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java @@ -66,11 +66,4 @@ public class VhncForm { @Column(name = "followup_previous") private Boolean followupPrevius; - @Column(name = "synced_by") - private String syncedBy; - - @org.hibernate.annotations.CreationTimestamp - @Column(name = "synced_date") - private Timestamp syncedDate; - } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index efa1d29fe..6950a8425 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -139,7 +139,7 @@ public void checkAndAddJsyIncentive(List delOutList) { IncentiveActivity institutionalDeliveryActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MH_MOTIVATE_INST_DEL", GroupName.MATERNAL_HEALTH.getDisplayName()); IncentiveActivity institutionalDeliveryActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("INST_DELIVERY_ESCORT", GroupName.ACTIVITY.getDisplayName()); if (deliveryOutcome.getPlaceOfDelivery() != null) { - String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if (placeOfDelivery != null && (!placeOfDelivery.equalsIgnoreCase("home") || @@ -170,7 +170,7 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getDeliveryOutcome() == 1) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); if (deliveryOutcome.getPlaceOfDelivery() != null) { - String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if(placeOfDelivery != null && (!placeOfDelivery.equalsIgnoreCase("home") || !placeOfDelivery.equalsIgnoreCase("in transit") || @@ -188,7 +188,7 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getDeliveryOutcome() == 2) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY2); if (deliveryOutcome.getPlaceOfDelivery() != null) { - String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if(placeOfDelivery != null && (!placeOfDelivery.equalsIgnoreCase("home") || !placeOfDelivery.equalsIgnoreCase("in transit") || @@ -206,7 +206,7 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getDeliveryOutcome() == 3) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY3); if (deliveryOutcome.getPlaceOfDelivery() != null) { - String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if(placeOfDelivery != null && (!placeOfDelivery.equalsIgnoreCase("home") || !placeOfDelivery.equalsIgnoreCase("in transit") || @@ -223,7 +223,7 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getDeliveryOutcome() == 4) { createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY4); if (deliveryOutcome.getPlaceOfDelivery() != null) { - String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if(placeOfDelivery != null && (!placeOfDelivery.equalsIgnoreCase("home") || !placeOfDelivery.equalsIgnoreCase("in transit") || From f588eee95a1a52eb8401e35f4bde2fec01b6f8a1 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 5 Oct 2026 17:00:08 +0530 Subject: [PATCH 182/237] fix dto issue --- .../java/com/iemr/flw/dto/iemr/ANCVisitDTO.java | 3 +++ .../iemr/flw/dto/iemr/AdolescentHealthDTO.java | 3 +++ .../iemr/flw/dto/iemr/AncCounsellingCareDTO.java | 3 +++ src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/ChildRegisterDTO.java | 3 +++ .../iemr/flw/dto/iemr/ChildVaccinationDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/DewormingFormDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/DynamicFormDTO.java | 3 +++ .../flw/dto/iemr/EligibleCoupleTrackingDTO.java | 3 +++ .../iemr/flw/dto/iemr/FilariasisCampaignDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/FormResponseDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/FormSectionDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/FormVersionDTO.java | 3 +++ .../java/com/iemr/flw/dto/iemr/HbncPart1DTO.java | 3 +++ .../java/com/iemr/flw/dto/iemr/HbncPart2DTO.java | 3 +++ .../com/iemr/flw/dto/iemr/HbncVisitCardDTO.java | 3 +++ .../java/com/iemr/flw/dto/iemr/HbncVisitDTO.java | 3 +++ src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/HighRiskAssessDTO.java | 3 +++ .../java/com/iemr/flw/dto/iemr/IRSRoundDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/IfaDistributionDTO.java | 3 +++ .../iemr/flw/dto/iemr/IncentiveActivityDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/LeprosyFollowUpDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/MalariaFollowUpDTO.java | 3 +++ src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/MicroBirthPlanDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/NotificationDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/OptionConditionDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/OrsDistributionDTO.java | 3 +++ .../java/com/iemr/flw/dto/iemr/PNCVisitDTO.java | 3 +++ src/main/java/com/iemr/flw/dto/iemr/PmsmaDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/QuestionOptionDTO.java | 3 +++ .../iemr/flw/dto/iemr/QuestionResponseDTO.java | 3 +++ .../iemr/flw/dto/iemr/QuestionValidationDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/SectionQuestionDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/SectionResponseDTO.java | 3 +++ .../iemr/flw/dto/iemr/StopTBRegistrationDto.java | 3 +++ .../com/iemr/flw/dto/iemr/TBScreeningDTO.java | 3 +++ .../com/iemr/flw/dto/iemr/TBSuspectedDTO.java | 3 +++ .../java/com/iemr/flw/dto/iemr/VHNDFormDTO.java | 3 +++ .../java/com/iemr/flw/dto/iemr/VaccineDTO.java | 3 +++ .../flw/service/impl/IncentiveServiceImpl.java | 9 --------- .../impl/SupervisorDashboardServiceImpl.java | 15 +++------------ 43 files changed, 126 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java index b4cf0033a..c82009cf1 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java @@ -9,6 +9,9 @@ @Data public class ANCVisitDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/AdolescentHealthDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AdolescentHealthDTO.java index b59bb8eaf..e534fd252 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/AdolescentHealthDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/AdolescentHealthDTO.java @@ -8,6 +8,9 @@ import java.util.List; @Data public class AdolescentHealthDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + @NotNull(message = "User ID cannot be null") Integer userId; @NotNull(message = "Adolescent health records cannot be null") diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java index b71086e0a..3f3011d3f 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java @@ -4,6 +4,9 @@ @Data public class AncCounsellingCareDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private String formId; private Long id ; private Long beneficiaryId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java b/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java index e39f06412..0654b5e3f 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java @@ -9,6 +9,9 @@ @Data public class CdrDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/ChildRegisterDTO.java b/src/main/java/com/iemr/flw/dto/iemr/ChildRegisterDTO.java index bcc26ff3a..9633a4b2b 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/ChildRegisterDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/ChildRegisterDTO.java @@ -6,6 +6,9 @@ @Data public class ChildRegisterDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/ChildVaccinationDTO.java b/src/main/java/com/iemr/flw/dto/iemr/ChildVaccinationDTO.java index d1fb5501b..fab5bc4e7 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/ChildVaccinationDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/ChildVaccinationDTO.java @@ -8,6 +8,9 @@ @Data @JsonIgnoreProperties(ignoreUnknown = true) public class ChildVaccinationDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private long id; private Long beneficiaryRegId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/DewormingFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DewormingFormDTO.java index bf77cd658..3c3feb613 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DewormingFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DewormingFormDTO.java @@ -4,6 +4,9 @@ @Data public class DewormingFormDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private int id = 0; private String dewormingDone; private String dewormingDate; diff --git a/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java index c9ecb63c4..9d755546a 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java @@ -39,6 +39,9 @@ @NoArgsConstructor @AllArgsConstructor public class DynamicFormDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long formId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java b/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java index 6d7a8a5d3..e3e88c1bd 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleTrackingDTO.java @@ -7,6 +7,9 @@ @Data public class EligibleCoupleTrackingDTO implements Serializable { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java index 2e53ee290..fda157d0d 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java @@ -4,6 +4,9 @@ @Data public class FilariasisCampaignDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private String visitDate; private FilariasisCampaignListDTO fields; 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 d53a5823a..efc74085b 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java @@ -39,6 +39,9 @@ @AllArgsConstructor @Builder public class FormResponseDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long responseId; private Long beneficiaryId; 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 6bb107958..52cc7405d 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java @@ -39,6 +39,9 @@ @NoArgsConstructor @AllArgsConstructor public class FormSectionDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long sectionId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/FormVersionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FormVersionDTO.java index 742b0f7b1..b7a042e8b 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/FormVersionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/FormVersionDTO.java @@ -32,6 +32,9 @@ @NoArgsConstructor @AllArgsConstructor public class FormVersionDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long versionId; private Integer versionNumber; diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbncPart1DTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbncPart1DTO.java index 05fcff99b..46891d740 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbncPart1DTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbncPart1DTO.java @@ -6,6 +6,9 @@ @Data public class HbncPart1DTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbncPart2DTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbncPart2DTO.java index 9a1becc62..0b1a9a05a 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbncPart2DTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbncPart2DTO.java @@ -6,6 +6,9 @@ @Data public class HbncPart2DTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbncVisitCardDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbncVisitCardDTO.java index 6ebb7ef70..59ad402c0 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbncVisitCardDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbncVisitCardDTO.java @@ -6,6 +6,9 @@ @Data public class HbncVisitCardDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java index a5043b22c..2bbc345a1 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbncVisitDTO.java @@ -9,6 +9,9 @@ @Data public class HbncVisitDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + @SerializedName("id") private Integer id; diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java index 9a983b508..a3b814d92 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java @@ -21,6 +21,9 @@ @Data public class HbycDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + @SerializedName("visit_day") private String visit_day; // 3 Months, 6 Months, etc. diff --git a/src/main/java/com/iemr/flw/dto/iemr/HighRiskAssessDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HighRiskAssessDTO.java index a2f32c607..5d0fed84a 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HighRiskAssessDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HighRiskAssessDTO.java @@ -6,6 +6,9 @@ @Data public class HighRiskAssessDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Integer userId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/IRSRoundDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IRSRoundDTO.java index f2d487160..89ee050d8 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IRSRoundDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IRSRoundDTO.java @@ -14,6 +14,9 @@ @NoArgsConstructor @AllArgsConstructor public class IRSRoundDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; @NotNull(message = "Date cannot be null") private LocalDate date; diff --git a/src/main/java/com/iemr/flw/dto/iemr/IfaDistributionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IfaDistributionDTO.java index 321437537..d9b0004d5 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IfaDistributionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IfaDistributionDTO.java @@ -5,6 +5,9 @@ @Data public class IfaDistributionDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + @SerializedName("beneficiaryId") private Long beneficiaryId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java index 7aa856463..b7d8b4578 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveActivityDTO.java @@ -8,6 +8,9 @@ @Data public class IncentiveActivityDTO implements Serializable { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; diff --git a/src/main/java/com/iemr/flw/dto/iemr/LeprosyFollowUpDTO.java b/src/main/java/com/iemr/flw/dto/iemr/LeprosyFollowUpDTO.java index aaf28a291..17686fced 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/LeprosyFollowUpDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/LeprosyFollowUpDTO.java @@ -6,6 +6,9 @@ @Data public class LeprosyFollowUpDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/MalariaFollowUpDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MalariaFollowUpDTO.java index f47da8ed8..b2b8054dd 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MalariaFollowUpDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MalariaFollowUpDTO.java @@ -29,6 +29,9 @@ import java.util.List; @Data public class MalariaFollowUpDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Integer userId; private List malariaFollowListUp; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java index e59047aba..136ae9877 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java @@ -6,6 +6,9 @@ @Data public class MdsrDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/MicroBirthPlanDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MicroBirthPlanDTO.java index 882cee359..2a6711e2a 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MicroBirthPlanDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MicroBirthPlanDTO.java @@ -7,6 +7,9 @@ import java.util.List; @Data public class MicroBirthPlanDTO implements Serializable { + private String syncedBy; + private java.sql.Timestamp syncedDate; + Integer userId; List entries; diff --git a/src/main/java/com/iemr/flw/dto/iemr/NotificationDTO.java b/src/main/java/com/iemr/flw/dto/iemr/NotificationDTO.java index b20dd7155..cf6e48ee0 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/NotificationDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/NotificationDTO.java @@ -6,6 +6,9 @@ @Data public class NotificationDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private String title; private String body; private String token; diff --git a/src/main/java/com/iemr/flw/dto/iemr/OptionConditionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OptionConditionDTO.java index d43167a78..6cd86e776 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/OptionConditionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/OptionConditionDTO.java @@ -38,6 +38,9 @@ @NoArgsConstructor @AllArgsConstructor public class OptionConditionDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long conditionId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionDTO.java index 7bdfd4fd2..0b4143b89 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionDTO.java @@ -4,6 +4,9 @@ @Data public class OrsDistributionDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long beneficiaryId; private Long houseHoldId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/PNCVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PNCVisitDTO.java index 9bfc4fc74..8829cfd7d 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/PNCVisitDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/PNCVisitDTO.java @@ -6,6 +6,9 @@ @Data public class PNCVisitDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; // private Integer pncVisit; diff --git a/src/main/java/com/iemr/flw/dto/iemr/PmsmaDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PmsmaDTO.java index 5c0adfc93..f0b4f8f99 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/PmsmaDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/PmsmaDTO.java @@ -6,6 +6,9 @@ @Data public class PmsmaDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; private String rchNumber; 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 6682404a0..3c2b14409 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java @@ -38,6 +38,9 @@ @NoArgsConstructor @AllArgsConstructor public class QuestionOptionDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long optionId; 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 03f1622e1..1bcff9c96 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java @@ -37,6 +37,9 @@ @AllArgsConstructor @Builder public class QuestionResponseDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long questionResponseId; private Long questionId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/QuestionValidationDTO.java b/src/main/java/com/iemr/flw/dto/iemr/QuestionValidationDTO.java index 72c144c53..594c8e6e1 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/QuestionValidationDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionValidationDTO.java @@ -36,6 +36,9 @@ @NoArgsConstructor @AllArgsConstructor public class QuestionValidationDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long validationId; 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 11a814303..720b4e266 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java @@ -40,6 +40,9 @@ @NoArgsConstructor @AllArgsConstructor public class SectionQuestionDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long questionId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/SectionResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/SectionResponseDTO.java index 78c918fe8..26b27324d 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/SectionResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/SectionResponseDTO.java @@ -39,6 +39,9 @@ @AllArgsConstructor @Builder public class SectionResponseDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long sectionResponseId; private Long sectionId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/StopTBRegistrationDto.java b/src/main/java/com/iemr/flw/dto/iemr/StopTBRegistrationDto.java index 64194ff1d..84984e2dd 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/StopTBRegistrationDto.java +++ b/src/main/java/com/iemr/flw/dto/iemr/StopTBRegistrationDto.java @@ -5,6 +5,9 @@ @Data public class StopTBRegistrationDto { + private String syncedBy; + private java.sql.Timestamp syncedDate; + // Standard beneficiary fields — forwarded to Common-API @JsonRawValue diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java index b81ca1c1f..7ff3d94f2 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java @@ -7,6 +7,9 @@ @Data public class TBScreeningDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Long benId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java index d09fa9bf8..23e568ef7 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java @@ -6,6 +6,9 @@ @Data public class TBSuspectedDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private Long id; private Timestamp updateDate; diff --git a/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java index bee7f2475..aa99186a1 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java @@ -29,6 +29,9 @@ @Data public class VHNDFormDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private String vhndDate; private String place; private Integer noOfBeneficiariesAttended; diff --git a/src/main/java/com/iemr/flw/dto/iemr/VaccineDTO.java b/src/main/java/com/iemr/flw/dto/iemr/VaccineDTO.java index a3019210b..5f91cdde6 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/VaccineDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/VaccineDTO.java @@ -6,6 +6,9 @@ @Data @JsonIgnoreProperties(ignoreUnknown = true) public class VaccineDTO { + private String syncedBy; + private java.sql.Timestamp syncedDate; + private short vaccineId; private String immunizationService; diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 4da29ff43..9e9e4b882 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -494,15 +494,6 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .filter(record -> validActivityIds.contains(record.getActivityId()) ) - .filter(record -> - !Boolean.TRUE.equals( - record.getIsDefaultActivity() - ) - - || Boolean.TRUE.equals( - record.getIsApproved() - ) - ) .collect(Collectors.toList()); }else if(request.getApprovalStatus().equals(104)){ records = records.stream() diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index cc287117d..b5350da32 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1235,13 +1235,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci incentiveActivityRecord = dbRecords.stream() - .filter(record -> - Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals( - record.getApprovalStatus(), 105 - ) - ) - .peek(record -> { if (Objects.equals(record.getApprovalStatus(), 102) && Boolean.TRUE.equals( @@ -1264,11 +1257,9 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci .filter(record -> - !Boolean.TRUE.equals( - record.getIsDefaultActivity() - ) - || Boolean.TRUE.equals( - record.getIsApproved() + Objects.equals(record.getApprovalStatus(), 102) + || Objects.equals( + record.getApprovalStatus(), 105 ) ) .collect(Collectors.toList()); From 08677fec83115a3ab5dd8f73145dae691baffb31 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 5 Oct 2026 17:31:11 +0530 Subject: [PATCH 183/237] fix dto issue --- src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleDTO.java | 3 +++ src/main/java/com/iemr/flw/dto/iemr/PregnantWomanDTO.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleDTO.java b/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleDTO.java index 0ec1c876e..d2b004f40 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/EligibleCoupleDTO.java @@ -11,6 +11,9 @@ @Data public class EligibleCoupleDTO implements Serializable { + private String syncedBy; + private Timestamp syncedDate; + private Long id; diff --git a/src/main/java/com/iemr/flw/dto/iemr/PregnantWomanDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PregnantWomanDTO.java index 5240f6677..816db8ed7 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/PregnantWomanDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/PregnantWomanDTO.java @@ -6,6 +6,9 @@ @Data public class PregnantWomanDTO { + private String syncedBy; + private Timestamp syncedDate; + private Long id; private Long benId; From fded8f32097431172778cb9795b82a76c2b03e39 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 5 Oct 2026 18:23:57 +0530 Subject: [PATCH 184/237] tpt incentive logic --- .../iemr/flw/repo/iemr/TbTptFollowUpRepo.java | 3 + .../impl/DeliveryOutcomeServiceImpl.java | 20 +++---- .../impl/TBConfirmedCaseServiceImpl.java | 58 +++++++++++++++++++ 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/TbTptFollowUpRepo.java b/src/main/java/com/iemr/flw/repo/iemr/TbTptFollowUpRepo.java index f444d47a4..7e398affb 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/TbTptFollowUpRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/TbTptFollowUpRepo.java @@ -5,9 +5,12 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.sql.Timestamp; import java.util.List; @Repository public interface TbTptFollowUpRepo extends JpaRepository { List findByUserId(Integer userId); + + List findByBenIdAndRegimenTypeAndTreatmentStartDate(Long benId, String regimenType, Timestamp treatmentStartDate); } diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index 6950a8425..06b8c87f8 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -142,8 +142,8 @@ public void checkAndAddJsyIncentive(List delOutList) { String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if (placeOfDelivery != null && - (!placeOfDelivery.equalsIgnoreCase("home") || - !placeOfDelivery.equalsIgnoreCase("in transit") || + (!placeOfDelivery.equalsIgnoreCase("home") && + !placeOfDelivery.equalsIgnoreCase("in transit") && !placeOfDelivery.equalsIgnoreCase("other private hospital"))) { // Institutional delivery (eligible case) @@ -172,8 +172,8 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getPlaceOfDelivery() != null) { String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if(placeOfDelivery != null && - (!placeOfDelivery.equalsIgnoreCase("home") || - !placeOfDelivery.equalsIgnoreCase("in transit") || + (!placeOfDelivery.equalsIgnoreCase("home") && + !placeOfDelivery.equalsIgnoreCase("in transit") && !placeOfDelivery.equalsIgnoreCase("other private hospital"))){ createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); @@ -190,8 +190,8 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getPlaceOfDelivery() != null) { String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if(placeOfDelivery != null && - (!placeOfDelivery.equalsIgnoreCase("home") || - !placeOfDelivery.equalsIgnoreCase("in transit") || + (!placeOfDelivery.equalsIgnoreCase("home") && + !placeOfDelivery.equalsIgnoreCase("in transit") && !placeOfDelivery.equalsIgnoreCase("other private hospital"))){ createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); @@ -208,8 +208,8 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getPlaceOfDelivery() != null) { String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if(placeOfDelivery != null && - (!placeOfDelivery.equalsIgnoreCase("home") || - !placeOfDelivery.equalsIgnoreCase("in transit") || + (!placeOfDelivery.equalsIgnoreCase("home") && + !placeOfDelivery.equalsIgnoreCase("in transit") && !placeOfDelivery.equalsIgnoreCase("other private hospital"))){ createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); @@ -225,8 +225,8 @@ public void checkAndAddJsyIncentive(List delOutList) { if (deliveryOutcome.getPlaceOfDelivery() != null) { String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery().toLowerCase(); if(placeOfDelivery != null && - (!placeOfDelivery.equalsIgnoreCase("home") || - !placeOfDelivery.equalsIgnoreCase("in transit") || + (!placeOfDelivery.equalsIgnoreCase("home") && + !placeOfDelivery.equalsIgnoreCase("in transit") && !placeOfDelivery.equalsIgnoreCase("other private hospital"))){ createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); 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 3f2125331..d89d553bb 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -56,6 +56,9 @@ public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { @Autowired private TbReferralFollowUpRepo tbReferralFollowUpRepo; + @Autowired + private IncentiveLogicImpl incentiveLogic; + @Autowired private TbTptFollowUpRepo tbTptFollowUpRepo; public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository, @@ -417,6 +420,8 @@ public String saveTptFollowUp(TbTptFollowUpDTO requestDTO, String token) { } tbTptFollowUpRepo.save(tbTptFollowUp); + + createTptIncentiveIfEligible(tbTptFollowUp); } response.setResponse("TPT follow up saved successfully"); @@ -431,6 +436,59 @@ public String saveTptFollowUp(TbTptFollowUpDTO requestDTO, String token) { } + private static final Map MIN_FOLLOW_UPS = Map.of( + "1HP", 1, + "3HP", 3, + "3RH", 3, + "4R", 4, + "6H", 6, + "6LFX", 6 + ); + + + private void createTptIncentiveIfEligible(TbTptFollowUp saved) { + + // 1. Basic conditions + if (!Boolean.TRUE.equals(saved.getTreatmentCompleted()) + || saved.getActualTreatmentCompletionDate() == null + || saved.getRegimenType() == null + || saved.getTreatmentStartDate() == null + || saved.getBenId() == null) { + return; + } + + // 2. Regimen ka minimum follow-up count + Integer minRequired = MIN_FOLLOW_UPS.get(saved.getRegimenType().trim().toUpperCase()); + if (minRequired == null) { + return; // unknown regimen + } + + // 3. Isi cycle ke saare follow-ups + List cycleRows = tbTptFollowUpRepo + .findByBenIdAndRegimenTypeAndTreatmentStartDate( + saved.getBenId(), + saved.getRegimenType(), + saved.getTreatmentStartDate()); + + long completedMonths = cycleRows.stream() + .map(TbTptFollowUp::getFollowUpMonth) + .filter(Objects::nonNull) + .map(String::trim) + .distinct() + .count(); + + if (completedMonths < minRequired) { + return; + } + Timestamp completionDate = saved.getActualTreatmentCompletionDate(); + + incentiveLogic.incentiveForTbPreventiveFollowUp( + saved.getBenId(), + completionDate, + completionDate, + saved.getUserId()); + } + @Override public String getTptFollowUp(String token) { From b525a5f07675e82658e56f439e162a7bf3be62a9 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 5 Oct 2026 18:59:51 +0530 Subject: [PATCH 185/237] tpt incentive logic --- src/main/java/com/iemr/flw/domain/iemr/TBScreening.java | 6 ++++++ .../iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java index c08f12775..01170cf91 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java @@ -213,4 +213,10 @@ public class TBScreening { @org.hibernate.annotations.CreationTimestamp @Column(name = "synced_date") private Timestamp syncedDate; + + @Column(name = "failure_to_gainWeight") + private Boolean failureToGainWeight; + + @Column(name = "decreased_activity_playfulness ") + private Boolean decreasedActivityOrPlayfulness ; } 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 d89d553bb..1bbc5ec00 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -463,7 +463,6 @@ private void createTptIncentiveIfEligible(TbTptFollowUp saved) { return; // unknown regimen } - // 3. Isi cycle ke saare follow-ups List cycleRows = tbTptFollowUpRepo .findByBenIdAndRegimenTypeAndTreatmentStartDate( saved.getBenId(), From 9e3dd3b13a7f3fad8dbc1623a0d87137837948a7 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 5 Oct 2026 19:21:19 +0530 Subject: [PATCH 186/237] tpt incentive logic --- src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java index 7ff3d94f2..4a1936d45 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java @@ -1,5 +1,6 @@ package com.iemr.flw.dto.iemr; +import jakarta.persistence.Column; import lombok.Data; import java.sql.Timestamp; @@ -90,5 +91,7 @@ public class TBScreeningDTO { private String hivStatus; private List keyPopulationRiskFactorIds; private List keyPopulationRiskFactors; + private Boolean failureToGainWeight; + private Boolean decreasedActivityOrPlayfulness ; } \ No newline at end of file From 4dc24594a2386e89deb1a11ed8e7aa8e0f12a91e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 12:26:55 +0530 Subject: [PATCH 187/237] tpt incentive logic --- .../impl/SupervisorDashboardServiceImpl.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index b5350da32..e6248292e 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -864,7 +864,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci } logger.info("Other:" + rows); - long pending = 0, verified = 0, rejected = 0 , unclaimedCount = 0 , overDue = 0 ; long overallVerified = 0, overallRejected = 0, overallPending = 0 , overallUnclaimed=0 ,overallOverDue =0; @@ -881,6 +880,22 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci for (Object[] row : rows) { + long pending = 0; + long verified = 0; + long rejected = 0; + long unclaimedCount = 0; + long overDue = 0; + + if (verified > 0) overallVerified++; + if (rejected > 0) overallRejected++; + + if (pending > 0) { + overallPending++; + } + + if (unclaimedCount > 0) overallUnclaimed++; + if (overDue > 0) overallOverDue++; + Map asha = new HashMap<>(); Integer ashaId = ((Number) row[0]).intValue(); From 8350ac1ab29ab7d463523e80eb9ff2ec431eab08 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 12:27:39 +0530 Subject: [PATCH 188/237] tpt incentive logic --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index e6248292e..b17359ad5 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -886,15 +886,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci long unclaimedCount = 0; long overDue = 0; - if (verified > 0) overallVerified++; - if (rejected > 0) overallRejected++; - - if (pending > 0) { - overallPending++; - } - - if (unclaimedCount > 0) overallUnclaimed++; - if (overDue > 0) overallOverDue++; Map asha = new HashMap<>(); From 6f364d27a3e3fc5f9e2b49a53f0d8a84c3944349 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 14:54:23 +0530 Subject: [PATCH 189/237] tpt incentive logic --- .../flw/repo/iemr/IncentiveRecordRepo.java | 15 ++- .../flw/service/impl/CoupleServiceImpl.java | 23 ++-- .../impl/SupervisorDashboardServiceImpl.java | 111 ++++++++++++++++-- 3 files changed, 127 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index bc6587dea..fd338de98 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -588,4 +588,17 @@ int resetRejectedIncentivesForNewMonth( @Param("updatedDate") Timestamp updatedDate, @Param("updatedBy") String updatedBy ); -} + + @Query("SELECT r FROM IncentiveActivityRecord r " + + "WHERE r.ashaId = :ashaId " + + "AND r.approvalStatus = :status " + + "AND r.startDate >= :start AND r.startDate < :end " + + "AND (r.isEligible = true OR r.isEligible IS NULL) " + + "AND (r.isClaimed = false OR r.isClaimed IS NULL)") + List findApprovedForMonth( + @Param("ashaId") Integer ashaId, + @Param("status") Integer status, + @Param("start") Timestamp start, + @Param("end") Timestamp end);} + + diff --git a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java index b650dd430..e12a1c87c 100644 --- a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java @@ -335,20 +335,25 @@ private void checkIncentiveForChildGap(Integer stateId, String userName,List getAshasAtFacility(Integer supervisorId, Integer faci - if (verified > 0) overallVerified += 1; - if (rejected > 0) overallRejected += 1; + // totalAmount skip wale block aur "pending == 0 && ... continue" ke baad + if (verified > 0) overallVerified++; + if (rejected > 0) overallRejected++; if (pending > 0) { - if (isOverDue) { - overallOverDue++; - } else { - overallPending++; - } + if (isOverDue) overallOverDue++; else overallPending++; } + if (unclaimedCount > 0) overallUnclaimed++; if (unclaimedCount > 0) overallUnclaimed += 1; @@ -1525,6 +1526,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci approvalStatus.put("pending", overallPending); approvalStatus.put("rejected", overallRejected); approvalStatus.put("unClaimed", overallUnclaimed); + approvalStatus.put("overDue", overallOverDue); response.put("approvalStatus", approvalStatus); response.put("data", ashaList); @@ -1716,6 +1718,33 @@ public int updateApprovalStatus(Integer ashaId, ashaSupervisorUserId, ashaSupervisorDetails ); + + boolean isApproved = !approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode()); + + // Final approval: AM mein supervisor/CHO, CG mein sirf ANM + // (CG mein ASHA Supervisor ka status 105 intermediate hai, uspar payment nahi) + boolean isFinalApprover = + ashaSupervisorDetails.getStateId().equals(StateCode.AM.getStateCode()) + || (ashaSupervisorDetails.getStateId().equals(StateCode.CG.getStateCode()) + && "ANM".equalsIgnoreCase(ashaSupervisorDetails.getRoleName())); + + if (isApproved && isFinalApprover) { + List approvedRecords; + + if (incentiveIds == null || incentiveIds.trim().isEmpty()) { + approvedRecords = incentiveRecordRepo + .findApprovedForMonth( + ashaId, approvalStatus, startDate, endDate); + } else { + List ids = Arrays.stream(incentiveIds.split(",")) + .map(String::trim).filter(v -> !v.isEmpty()) + .map(Long::valueOf).collect(Collectors.toList()); + approvedRecords = incentiveRecordRepo.findAllById(ids); + } + + triggerPayment(ashaId, month, year, approvedRecords, + ashaSupervisorDetails, ashaSupervisorUserId); + } } return updatedCount; @@ -1793,6 +1822,64 @@ private void sendApprovalNotification( } } + public void triggerPayment(Integer ashaId, Integer month, Integer year, + List approvedRecords, + UserServiceRoleDTO supervisor, Integer supervisorUserId) { + try { + if (approvedRecords == null || approvedRecords.isEmpty()) { + logger.info("No approved records, payment not triggered for asha {}", ashaId); + return; + } + + LocalDate first = LocalDate.of(year, month, 1); + Period period = new Period(); + period.setStart(first.toString()); // 2026-01-01 + period.setEnd(first.withDayOfMonth(first.lengthOfMonth()).toString()); // 2026-01-31 + + VerifiedBy verifiedBy = new VerifiedBy(); + verifiedBy.setEmployeeId(String.valueOf(supervisorUserId)); + verifiedBy.setName(supervisor.getUserName()); + + // activity wise group: count + total amount + Map> byActivity = approvedRecords.stream() + .collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); + + List items = new ArrayList<>(); + byActivity.forEach((activityId, recs) -> { + long count = recs.size(); + long total = recs.stream() + .mapToLong(r -> r.getAmount() == null ? 0L : r.getAmount()) + .sum(); + + PaymentItem item = new PaymentItem(); + item.setActivityCode(String.valueOf(activityId)); // ya activity ka code field + item.setCount(String.valueOf(count)); + item.setIncentiveAmount(String.valueOf(total)); + items.add(item); + }); + + String timestamp = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")) + .truncatedTo(ChronoUnit.SECONDS) + .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); // 2026-02-01T02:00:00+05:30 + + PaymentRequest paymentRequest = new PaymentRequest( + UUID.randomUUID().toString(), + "AMRIT", + period, + String.valueOf(ashaId), + timestamp, + verifiedBy, + items + ); + + logger.info("PAYMENT REQUEST Payload: {}", new Gson().toJson(paymentRequest)); + paymentService.sendPaymentRequest(paymentRequest); + + } catch (Exception e) { + // payment fail hone par approval rollback nahi hona chahiye + logger.error("Payment request failed for asha {}: {}", ashaId, e.getMessage(), e); + } + } private JSONObject buildEmptyIncentiveSummary() { JSONObject summary = new JSONObject(); summary.put("verified", 0); From 85176ee7ccba4d1cfa6fdeb342be24832dc28933 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 14:56:13 +0530 Subject: [PATCH 190/237] tpt incentive logic --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 8 ++++++-- .../com/iemr/flw/service/impl/UTPReronaPaymentJob.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 0ff9fa4fc..1551c1296 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1464,7 +1464,6 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci - // totalAmount skip wale block aur "pending == 0 && ... continue" ke baad if (verified > 0) overallVerified++; if (rejected > 0) overallRejected++; if (pending > 0) { @@ -1825,6 +1824,12 @@ private void sendApprovalNotification( public void triggerPayment(Integer ashaId, Integer month, Integer year, List approvedRecords, UserServiceRoleDTO supervisor, Integer supervisorUserId) { + + logger.info("========================================"); + + logger.info("SSD Request Send to portal"); + + logger.info("========================================"); try { if (approvedRecords == null || approvedRecords.isEmpty()) { logger.info("No approved records, payment not triggered for asha {}", ashaId); @@ -1876,7 +1881,6 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, paymentService.sendPaymentRequest(paymentRequest); } catch (Exception e) { - // payment fail hone par approval rollback nahi hona chahiye logger.error("Payment request failed for asha {}: {}", ashaId, e.getMessage(), e); } } diff --git a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java index 30a791020..3edb88456 100644 --- a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java +++ b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java @@ -49,7 +49,7 @@ public void run(String... args) { log.info("FLW application started successfully and is now running."); log.info("========================================"); - triggerStaticPayment(); + // triggerStaticPayment(); } // ✅ Separate method — call this for immediate testing From 22ea14d0b8802ad209ba72935fde8c0086110b30 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 15:29:54 +0530 Subject: [PATCH 191/237] tpt incentive logic --- .../flw/service/impl/SupervisorDashboardServiceImpl.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 1551c1296..4b23a0a9a 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1265,9 +1265,7 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }) - .filter(record -> - Objects.equals(record.getApprovalStatus(), 102) - || Objects.equals( + .filter(record -> Objects.equals( record.getApprovalStatus(), 105 ) ) @@ -1842,7 +1840,7 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, period.setEnd(first.withDayOfMonth(first.lengthOfMonth()).toString()); // 2026-01-31 VerifiedBy verifiedBy = new VerifiedBy(); - verifiedBy.setEmployeeId(String.valueOf(supervisorUserId)); + verifiedBy.setEmployeeId("NRHM-"+supervisorUserId); verifiedBy.setName(supervisor.getUserName()); // activity wise group: count + total amount From 9a381e7a0f445703d1f044487c2e25f737d8c906 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 15:42:18 +0530 Subject: [PATCH 192/237] fix approval staus issue --- .../impl/SupervisorDashboardServiceImpl.java | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 4b23a0a9a..74f5df80f 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1243,34 +1243,29 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci if (Objects.equals(approvalStatusID, 102)) { incentiveActivityRecord = dbRecords.stream() - .peek(record -> { if (Objects.equals(record.getApprovalStatus(), 102) - && Boolean.TRUE.equals( - record.getIsDefaultActivity() - ) - && Boolean.TRUE.equals( - record.getIsApproved() - )) { + && Boolean.TRUE.equals(record.getIsDefaultActivity()) + && Boolean.TRUE.equals(record.getIsApproved())) { - logger.info( - "Changing record status 102 to 105: " + - "id={}, activityId={}", - record.getId(), - record.getActivityId() - ); + logger.info("Changing record status 102 to 105: id={}, activityId={}", + record.getId(), record.getActivityId()); record.setApprovalStatus(105); } }) + .filter(record -> { + boolean isDefault = Boolean.TRUE.equals(record.getIsDefaultActivity()); + Integer status = record.getApprovalStatus(); + // non-default aur 102 + boolean nonDefault102 = !isDefault && Objects.equals(status, 102); - .filter(record -> Objects.equals( - record.getApprovalStatus(), 105 - ) - ) - .collect(Collectors.toList()); + boolean is105 = Objects.equals(status, 105); + return nonDefault102 || is105; + }) + .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() .map(IncentiveActivityRecord::getAmount) .filter(Objects::nonNull) From ad11dd78f4d3c399980310f059e72c4c986e9927 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 16:17:51 +0530 Subject: [PATCH 193/237] fix approval staus issue --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 74f5df80f..81e7a3c7c 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1256,14 +1256,16 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci }) .filter(record -> { boolean isDefault = Boolean.TRUE.equals(record.getIsDefaultActivity()); + boolean isClaimed = Boolean.TRUE.equals(record.getIsClaimed()); Integer status = record.getApprovalStatus(); // non-default aur 102 boolean nonDefault102 = !isDefault && Objects.equals(status, 102); + // 105 (peek se badle hue default approved records bhi yahin aayenge) boolean is105 = Objects.equals(status, 105); - return nonDefault102 || is105; + return isClaimed && (nonDefault102 || is105); }) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() From 3b4cc2b93c64209f2ce9299095c60036b3e08bb9 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 16:27:26 +0530 Subject: [PATCH 194/237] fix approval staus issue --- .../service/impl/IncentiveServiceImpl.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 9e9e4b882..e140fc7e2 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -489,11 +489,38 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege } }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - if(request.getApprovalStatus().equals(102) || request.getApprovalStatus().equals(105)){ + Integer status = request.getApprovalStatus(); + + if (Integer.valueOf(102).equals(status) + || Integer.valueOf(105).equals(status)) { + records = records.stream() - .filter(record -> - validActivityIds.contains(record.getActivityId()) - ) + .filter(record -> validActivityIds.contains(record.getActivityId())) + + // 2. default + approved + 102 -> 105 + .peek(record -> { + if (Objects.equals(record.getApprovalStatus(), 102) + && Boolean.TRUE.equals(record.getIsDefaultActivity()) + && Boolean.TRUE.equals(record.getIsApproved())) { + + logger.info("Changing record status 102 to 105: id={}, activityId={}", + record.getId(), record.getActivityId()); + + record.setApprovalStatus(105); + } + }) + + // 3. final visibility + .filter(record -> { + boolean isDefault = Boolean.TRUE.equals(record.getIsDefaultActivity()); + boolean isClaimed = Boolean.TRUE.equals(record.getIsClaimed()); + Integer recStatus = record.getApprovalStatus(); + + boolean nonDefault102 = !isDefault && Objects.equals(recStatus, 102); + boolean is105 = Objects.equals(recStatus, 105); + + return isClaimed && (nonDefault102 || is105); + }) .collect(Collectors.toList()); }else if(request.getApprovalStatus().equals(104)){ records = records.stream() From 77fd3bbf077cfb4aa891f64b57065f50dc6cce7f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 16:37:31 +0530 Subject: [PATCH 195/237] fix approval staus issue --- .../iemr/flw/service/impl/IncentiveServiceImpl.java | 1 + .../service/impl/SupervisorDashboardServiceImpl.java | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index e140fc7e2..47e20bc12 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -204,6 +204,7 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { } @Override public String getAllIncentivesByUserId(GetBenRequestHandler request) { + int page = 0; int size = 200; // bumped from 20 — fewer round trips for large histories Page pageResult; diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 81e7a3c7c..8b147970e 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1258,14 +1258,15 @@ public Map getAshasAtFacility(Integer supervisorId, Integer faci boolean isDefault = Boolean.TRUE.equals(record.getIsDefaultActivity()); boolean isClaimed = Boolean.TRUE.equals(record.getIsClaimed()); Integer status = record.getApprovalStatus(); + boolean default105 = isDefault && Objects.equals(status, 105); - // non-default aur 102 - boolean nonDefault102 = !isDefault && Objects.equals(status, 102); - // 105 (peek se badle hue default approved records bhi yahin aayenge) - boolean is105 = Objects.equals(status, 105); + boolean nonDefault102Claimed = !isDefault && Objects.equals(status, 102) && isClaimed; + + boolean other105 = !isDefault && Objects.equals(status, 105); + + return nonDefault102Claimed || default105 || other105; - return isClaimed && (nonDefault102 || is105); }) .collect(Collectors.toList()); totalAmount = incentiveActivityRecord.stream() From 29e8a914181aace2cf8d85324b991a1985f11966 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 16:38:40 +0530 Subject: [PATCH 196/237] fix approval staus issue --- .../com/iemr/flw/service/impl/IncentiveServiceImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 47e20bc12..3e0dd7e83 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -204,7 +204,6 @@ public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { } @Override public String getAllIncentivesByUserId(GetBenRequestHandler request) { - int page = 0; int size = 200; // bumped from 20 — fewer round trips for large histories Page pageResult; @@ -517,10 +516,14 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege boolean isClaimed = Boolean.TRUE.equals(record.getIsClaimed()); Integer recStatus = record.getApprovalStatus(); - boolean nonDefault102 = !isDefault && Objects.equals(recStatus, 102); + // non-default, 102 aur claimed + boolean nonDefault102Claimed = + !isDefault && Objects.equals(recStatus, 102) && isClaimed; + + // koi bhi 105 (default ho ya non-default, claimed ho ya na ho) boolean is105 = Objects.equals(recStatus, 105); - return isClaimed && (nonDefault102 || is105); + return nonDefault102Claimed || is105; }) .collect(Collectors.toList()); }else if(request.getApprovalStatus().equals(104)){ From ebea387d1b8eb5f182964f23017b0d04dbefae02 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 16:59:49 +0530 Subject: [PATCH 197/237] fix approval staus issue --- .../service/impl/IncentiveServiceImpl.java | 13 +++----- .../impl/SupervisorDashboardServiceImpl.java | 32 ++++++++++++------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 3e0dd7e83..bdeae9e5c 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -497,7 +497,6 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege records = records.stream() .filter(record -> validActivityIds.contains(record.getActivityId())) - // 2. default + approved + 102 -> 105 .peek(record -> { if (Objects.equals(record.getApprovalStatus(), 102) && Boolean.TRUE.equals(record.getIsDefaultActivity()) @@ -514,16 +513,14 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Intege .filter(record -> { boolean isDefault = Boolean.TRUE.equals(record.getIsDefaultActivity()); boolean isClaimed = Boolean.TRUE.equals(record.getIsClaimed()); - Integer recStatus = record.getApprovalStatus(); + boolean default105 = isDefault && Objects.equals(status, 105); - // non-default, 102 aur claimed - boolean nonDefault102Claimed = - !isDefault && Objects.equals(recStatus, 102) && isClaimed; - // koi bhi 105 (default ho ya non-default, claimed ho ya na ho) - boolean is105 = Objects.equals(recStatus, 105); + boolean nonDefault102Claimed = !isDefault && Objects.equals(status, 102) && isClaimed; - return nonDefault102Claimed || is105; + boolean other105 = !isDefault && Objects.equals(status, 105); + + return nonDefault102Claimed || default105 || other105; }) .collect(Collectors.toList()); }else if(request.getApprovalStatus().equals(104)){ diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 8b147970e..f79744eb3 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -51,6 +51,9 @@ public class SupervisorDashboardServiceImpl implements SupervisorDashboardServic @Autowired private UserService userService; + @Autowired + EmployeeMasterRepo employeeMasterRepo; + @Autowired private NotificationService notificationService; @@ -1862,19 +1865,26 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, String timestamp = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")) .truncatedTo(ChronoUnit.SECONDS) .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); // 2026-02-01T02:00:00+05:30 + if(employeeMasterRepo.findUserByUserID(ashaId)!=null){ + String empId = employeeMasterRepo.findUserByUserID(ashaId).getEmployeeID(); + if(empId!=null){ + PaymentRequest paymentRequest = new PaymentRequest( + UUID.randomUUID().toString(), + "AMRIT", + period, + String.valueOf(empId), + timestamp, + verifiedBy, + items + ); + logger.info("PAYMENT REQUEST Payload: {}", new Gson().toJson(paymentRequest)); + paymentService.sendPaymentRequest(paymentRequest); + } + + } + - PaymentRequest paymentRequest = new PaymentRequest( - UUID.randomUUID().toString(), - "AMRIT", - period, - String.valueOf(ashaId), - timestamp, - verifiedBy, - items - ); - logger.info("PAYMENT REQUEST Payload: {}", new Gson().toJson(paymentRequest)); - paymentService.sendPaymentRequest(paymentRequest); } catch (Exception e) { logger.error("Payment request failed for asha {}: {}", ashaId, e.getMessage(), e); From 4cf82054a93fb811ffb7f6afa0400dfebf4d040d Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 17:10:35 +0530 Subject: [PATCH 198/237] fix approval staus issue --- .../service/impl/IncentiveServiceImpl.java | 320 +++++++----------- 1 file changed, 114 insertions(+), 206 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index bdeae9e5c..8ffa4f5da 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -360,297 +360,205 @@ public void resetRejectedIncentivesForPreviousMonths() { ); } // ================= GROUPED SUMMARY ================= - @Override - public String getAllIncentivesGroupedSummary(GetBenRequestHandler request,Integer userId) { - String roleName = userService.getUserDetail(userId).getRoleName(); - LocalDate start = LocalDate.of(request.getYear(), request.getMonth(), 1); - LocalDate end = start.withDayOfMonth(start.lengthOfMonth()); - + @Transactional(readOnly = true) + public String getAllIncentivesGroupedSummary(GetBenRequestHandler request, Integer userId) { - LocalDate monthStart = LocalDate.of( - request.getYear(), - request.getMonth(), - 1 - ); + String roleName = userService.getUserDetail(userId).getRoleName(); + Integer reqStatus = request.getApprovalStatus(); - Timestamp startTs = - Timestamp.valueOf(monthStart.atStartOfDay()); + Integer stateId = userRepo.getUserRole(request.getUserId()).get(0).getStateId(); + boolean isCG = stateId != null && stateId.intValue() == StateCode.CG.getStateCode(); - Timestamp nextMonthTs = - Timestamp.valueOf(monthStart.plusMonths(1).atStartOfDay()); + logger.info("Request getAllIncentivesGroupedSummary: {}", reqStatus); - Integer villageID = userRepo.getUserRole(request.getUserId()).get(0).getStateId(); - boolean isCG = villageID != null && villageID.intValue() == StateCode.CG.getStateCode(); - logger.info("Request getAllIncentivesGroupedSummary: "+request.getApprovalStatus()); List records = recordRepo.findRecordsByAsha(request.getUserId()) .stream() - .filter(r -> - r.getCreatedDate() != null - - // Month filter using createdDate - && r.getCreatedDate() - .toLocalDateTime() - .getMonthValue() - == request.getMonth() - - && r.getCreatedDate() - .toLocalDateTime() - .getYear() - == request.getYear() - - && Boolean.TRUE.equals(r.getIsClaimed()) - - && ( - // Overdue: 102, 104 or 105 - ( - Objects.equals( - request.getApprovalStatus(), - 104 - ) - && ( - Objects.equals( - r.getApprovalStatus(), - 102 - ) - || Objects.equals( - r.getApprovalStatus(), - 104 - ) - || Objects.equals( - r.getApprovalStatus(), - 105 - ) - ) - ) - - || - - // Verified: 101 or 105 - ( - Objects.equals( - request.getApprovalStatus(), - 105 - ) - && ( - Objects.equals( - r.getApprovalStatus(), - 101 - ) - || Objects.equals( - r.getApprovalStatus(), - 105 - ) - ) - ) - - || - - // Other statuses - ( - !Objects.equals( - request.getApprovalStatus(), - 104 - ) - && !Objects.equals( - request.getApprovalStatus(), - 105 - ) - && Objects.equals( - r.getApprovalStatus(), - request.getApprovalStatus() - ) - ) - ) - ) + .filter(r -> r.getCreatedDate() != null) + .filter(r -> { + LocalDateTime created = r.getCreatedDate().toLocalDateTime(); + return created.getMonthValue() == request.getMonth() + && created.getYear() == request.getYear(); + }) + .filter(r -> Boolean.TRUE.equals(r.getIsClaimed())) + .filter(r -> matchesRequestedStatus(r.getApprovalStatus(), reqStatus)) .collect(Collectors.toList()); - - // Bulk fetch valid activity IDs — state wise List activityIds = records.stream() .map(IncentiveActivityRecord::getActivityId) .collect(Collectors.toList()); - Set validActivityIds = isCG - ? incentivesRepo.findValidActivityIds(activityIds, true) - : incentivesRepo.findValidActivityIds(activityIds, false); + Set validActivityIds = incentivesRepo.findValidActivityIds(activityIds, isCG); + if (validActivityIds == null) { + validActivityIds = Collections.emptySet(); + } + final Set validIds = validActivityIds; + + if (isCG) { + + if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { - // Filter records based on valid activity IDs - if(isCG){ - if("ASHA Supervisor".equalsIgnoreCase(roleName)){ - if(request.getApprovalStatus().equals(104)){ + if (Integer.valueOf(104).equals(reqStatus)) { records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity() && r.getApprovalStatus().equals(102)) + .filter(r -> validIds.contains(r.getActivityId()) + && Boolean.TRUE.equals(r.getIsDefaultActivity()) + && Objects.equals(r.getApprovalStatus(), 102)) .collect(Collectors.toList()); - }else { + } else { records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId()) && r.getIsDefaultActivity()) + .filter(r -> validIds.contains(r.getActivityId()) + && Boolean.TRUE.equals(r.getIsDefaultActivity())) .collect(Collectors.toList()); } - }else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - Integer status = request.getApprovalStatus(); + } else if ("ANM".equalsIgnoreCase(roleName) || "CHO".equalsIgnoreCase(roleName)) { - if (Integer.valueOf(102).equals(status) - || Integer.valueOf(105).equals(status)) { + if (Integer.valueOf(102).equals(reqStatus) || Integer.valueOf(105).equals(reqStatus)) { records = records.stream() - .filter(record -> validActivityIds.contains(record.getActivityId())) + .filter(r -> validIds.contains(r.getActivityId())) - .peek(record -> { - if (Objects.equals(record.getApprovalStatus(), 102) - && Boolean.TRUE.equals(record.getIsDefaultActivity()) - && Boolean.TRUE.equals(record.getIsApproved())) { + // default + approved + 102 -> 105 + .peek(r -> { + if (Objects.equals(r.getApprovalStatus(), 102) + && Boolean.TRUE.equals(r.getIsDefaultActivity()) + && Boolean.TRUE.equals(r.getIsApproved())) { logger.info("Changing record status 102 to 105: id={}, activityId={}", - record.getId(), record.getActivityId()); - - record.setApprovalStatus(105); + r.getId(), r.getActivityId()); + r.setApprovalStatus(105); } }) - // 3. final visibility - .filter(record -> { - boolean isDefault = Boolean.TRUE.equals(record.getIsDefaultActivity()); - boolean isClaimed = Boolean.TRUE.equals(record.getIsClaimed()); - boolean default105 = isDefault && Objects.equals(status, 105); - - - boolean nonDefault102Claimed = !isDefault && Objects.equals(status, 102) && isClaimed; + .filter(r -> { + boolean isDefault = Boolean.TRUE.equals(r.getIsDefaultActivity()); + boolean isClaimed = Boolean.TRUE.equals(r.getIsClaimed()); + Integer recStatus = r.getApprovalStatus(); - boolean other105 = !isDefault && Objects.equals(status, 105); + if (Integer.valueOf(102).equals(reqStatus)) { + return (!isDefault && Objects.equals(recStatus, 102) && isClaimed) + || Objects.equals(recStatus, 105); + } - return nonDefault102Claimed || default105 || other105; + return Objects.equals(recStatus, 101) + || Objects.equals(recStatus, 105); }) .collect(Collectors.toList()); - }else if(request.getApprovalStatus().equals(104)){ - records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) - .filter(r -> { - if (Objects.equals(request.getApprovalStatus(), 104)) { - boolean isDefault = - Boolean.TRUE.equals(r.getIsDefaultActivity()); + } else if (Integer.valueOf(104).equals(reqStatus)) { - boolean isApproved = - Boolean.TRUE.equals(r.getIsApproved()); + records = records.stream() + .filter(r -> validIds.contains(r.getActivityId())) + .filter(r -> { + boolean isDefault = Boolean.TRUE.equals(r.getIsDefaultActivity()); + boolean isApproved = Boolean.TRUE.equals(r.getIsApproved()); - // All non-default 102 records, - // and approved default 102 records - boolean status102 = - Objects.equals(r.getApprovalStatus(), 102) - && (!isDefault || isApproved); + boolean status102 = Objects.equals(r.getApprovalStatus(), 102) + && (!isDefault || isApproved); - // Default 105 records, regardless of isApproved - boolean status105 = - Objects.equals(r.getApprovalStatus(), 105) - && isDefault; + boolean status105 = Objects.equals(r.getApprovalStatus(), 105) + && isDefault; - // Existing overdue records - boolean status104 = - Objects.equals(r.getApprovalStatus(), 104); - - return status102 || status105 || status104; - } + boolean status104 = Objects.equals(r.getApprovalStatus(), 104); - return Objects.equals( - r.getApprovalStatus(), - request.getApprovalStatus() - ); + return status102 || status105 || status104; }) .collect(Collectors.toList()); - }else { + + } else { records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) + .filter(r -> validIds.contains(r.getActivityId())) .collect(Collectors.toList()); } - - - - logger.info( - "ANM/CHO records after default activity filter: {}", - records.size() - ); + logger.info("ANM/CHO records after default activity filter: {}", records.size()); } - }else { + } else { records = records.stream() - .filter(r -> validActivityIds.contains(r.getActivityId())) + .filter(r -> validIds.contains(r.getActivityId())) .collect(Collectors.toList()); } - Map> grouped = records.stream().collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); List> result = new ArrayList<>(); - for (var entry : grouped.entrySet()) { + for (Map.Entry> entry : grouped.entrySet()) { Long activityId = entry.getKey(); List list = entry.getValue(); - IncentiveActivity activity = - incentivesRepo.findById(activityId).orElse(null); - - Integer approvalStatus = list.stream() - .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) - .map(IncentiveActivityRecord::getApprovalStatus) - .orElse(0); + IncentiveActivity activity = incentivesRepo.findById(activityId).orElse(null); + if (activity == null) continue; - boolean isApproved = list.stream() - .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) - .map(IncentiveActivityRecord::getIsApproved) - .orElse(false); - Long incentiveId = list.stream() + IncentiveActivityRecord latest = list.stream() .max(Comparator.comparing(IncentiveActivityRecord::getCreatedDate)) - .map(IncentiveActivityRecord::getId) .orElse(null); + if (latest == null) continue; - if (activity == null) continue; + Integer approvalStatus = latest.getApprovalStatus() != null ? latest.getApprovalStatus() : 0; + boolean isApproved = Boolean.TRUE.equals(latest.getIsApproved()); + Long incentiveId = latest.getId(); long total = list.stream() .mapToLong(r -> r.getAmount() != null ? r.getAmount() : 0) .sum(); Map map = new HashMap<>(); - if(isCG){ - map.put("activityId", activityId); - map.put("incentiveId",incentiveId); - map.put("activityDec", activity.getDescription()); - if(activity.getGroupCategoryName()!=null && !activity.getGroupCategoryName().isEmpty()){ + map.put("activityId", activityId); + map.put("incentiveId", incentiveId); + map.put("activityDec", activity.getDescription()); + map.put("claimCount", list.size()); + map.put("totalAmount", total); + map.put("amount", activity.getRate()); + + if (isCG) { + if (activity.getGroupCategoryName() != null && !activity.getGroupCategoryName().isEmpty()) { map.put("groupName", activity.getGroupCategoryName()); - - }else { + } else { map.put("groupName", activity.getGroup()); - } map.put("isDefault", activity.getIsDefaultActivity()); map.put("approvalStatus", approvalStatus); map.put("isApproved", isApproved); - map.put("claimCount", list.size()); - map.put("totalAmount", total); - map.put("amount", activity.getRate()); - - }else { - map.put("activityId", activityId); - map.put("incentiveId",incentiveId); - map.put("activityDec", activity.getDescription()); + } else { map.put("groupName", activity.getGroup()); - map.put("claimCount", list.size()); - map.put("totalAmount", total); - map.put("amount", activity.getRate()); - } result.add(map); + } + return new Gson().toJson(result); + } + /** + * Request ke status ke hisaab se kaunse DB status allow hain. + */ + private boolean matchesRequestedStatus(Integer recStatus, Integer reqStatus) { + if (Integer.valueOf(104).equals(reqStatus)) { + // Overdue tab: 102, 104, 105 + return Objects.equals(recStatus, 102) + || Objects.equals(recStatus, 104) + || Objects.equals(recStatus, 105); } - return new Gson().toJson(result); + if (Integer.valueOf(105).equals(reqStatus)) { + // Verified tab: 101, 105 + return Objects.equals(recStatus, 101) + || Objects.equals(recStatus, 105); + } + + if (Integer.valueOf(102).equals(reqStatus)) { + // Pending tab: 102, aur 105 (default approved records bhi yahin dikhte hain) + return Objects.equals(recStatus, 102) + || Objects.equals(recStatus, 105); + } + + // Baaki tabs (103 waghera): exact match + return Objects.equals(recStatus, reqStatus); } private boolean isAfter24Hours(Timestamp claimedDate) { From 86fdd55679f32e8259c5e64291d38f487a238e20 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 17:17:24 +0530 Subject: [PATCH 199/237] fix approval staus issue --- .../iemr/flw/service/impl/IncentiveServiceImpl.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 8ffa4f5da..5fb04d0bc 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -404,7 +404,14 @@ public String getAllIncentivesGroupedSummary(GetBenRequestHandler request, Integ && Boolean.TRUE.equals(r.getIsDefaultActivity()) && Objects.equals(r.getApprovalStatus(), 102)) .collect(Collectors.toList()); - } else { + } else if (Integer.valueOf(102).equals(reqStatus)) { + records = records.stream() + .filter(r -> validIds.contains(r.getActivityId()) + && Boolean.TRUE.equals(r.getIsDefaultActivity()) + && Objects.equals(r.getApprovalStatus(), 102)) + .collect(Collectors.toList()); + + }else { records = records.stream() .filter(r -> validIds.contains(r.getActivityId()) && Boolean.TRUE.equals(r.getIsDefaultActivity())) @@ -552,12 +559,10 @@ private boolean matchesRequestedStatus(Integer recStatus, Integer reqStatus) { } if (Integer.valueOf(102).equals(reqStatus)) { - // Pending tab: 102, aur 105 (default approved records bhi yahin dikhte hain) return Objects.equals(recStatus, 102) || Objects.equals(recStatus, 105); } - // Baaki tabs (103 waghera): exact match return Objects.equals(recStatus, reqStatus); } From d8edd9a8bcb7d082bc3b587114155a3a09dbad40 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 17:40:54 +0530 Subject: [PATCH 200/237] fix approval staus issue --- .../impl/SupervisorDashboardServiceImpl.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index f79744eb3..c18d2cc64 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -9,6 +9,7 @@ import java.util.stream.Collectors; import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.IncentiveActivity; import com.iemr.flw.domain.iemr.IncentiveActivityRecord; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.dto.iemr.Period; @@ -45,6 +46,9 @@ public class SupervisorDashboardServiceImpl implements SupervisorDashboardServic @Autowired private IncentiveRecordRepo incentiveRecordRepo; + @Autowired + private IncentivesRepo incentivesRepo; + @Autowired private JwtUtil jwtUtil; @@ -1844,7 +1848,6 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, verifiedBy.setEmployeeId("NRHM-"+supervisorUserId); verifiedBy.setName(supervisor.getUserName()); - // activity wise group: count + total amount Map> byActivity = approvedRecords.stream() .collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); @@ -1856,8 +1859,12 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, .sum(); PaymentItem item = new PaymentItem(); - item.setActivityCode(String.valueOf(activityId)); // ya activity ka code field - item.setCount(String.valueOf(count)); + item.setActivityCode( + incentivesRepo.findById(activityId) + .map(activity -> String.valueOf(activity.getStateActivityCode())) + .orElse(null) + ); item.setCount(String.valueOf(count)); + item.setIncentiveAmount(String.valueOf(total)); items.add(item); }); @@ -1872,7 +1879,7 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, UUID.randomUUID().toString(), "AMRIT", period, - String.valueOf(empId), + String.valueOf(1857708), timestamp, verifiedBy, items From bc779a02bd334632c22e49ee510937b90fe97701 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 6 Oct 2026 18:01:32 +0530 Subject: [PATCH 201/237] fix approval staus issue --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index c18d2cc64..2affddc01 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1845,7 +1845,7 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, period.setEnd(first.withDayOfMonth(first.lengthOfMonth()).toString()); // 2026-01-31 VerifiedBy verifiedBy = new VerifiedBy(); - verifiedBy.setEmployeeId("NRHM-"+supervisorUserId); + verifiedBy.setEmployeeId("NRHM-"+54374); verifiedBy.setName(supervisor.getUserName()); Map> byActivity = approvedRecords.stream() From 6e4177175f04412d16433b90fd4e8ad334d48dd6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 7 Oct 2026 11:36:08 +0530 Subject: [PATCH 202/237] fix approval staus issue --- .../flw/repo/iemr/IncentiveRecordRepo.java | 311 +++++++++--------- .../impl/SupervisorDashboardServiceImpl.java | 2 +- 2 files changed, 155 insertions(+), 158 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index fd338de98..74acfa5f8 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -100,18 +100,18 @@ List getStatusCountByAshaIdANM( @Param("endDate") Timestamp endDate); @Query(""" -SELECT - SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), - SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), - SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), - SUM(CASE WHEN record.approvalStatus IN (101,105) THEN 1 ELSE 0 END) -FROM IncentiveActivityRecord record -WHERE record.ashaId = :ashaId -AND record.isClaimed = true -AND record.isDefaultActivity = true -AND record.createdDate >= :startDate -AND record.createdDate < :endDate -""") + SELECT + SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus IN (101,105) THEN 1 ELSE 0 END) + FROM IncentiveActivityRecord record + WHERE record.ashaId = :ashaId + AND record.isClaimed = true + AND record.isDefaultActivity = true + AND record.createdDate >= :startDate + AND record.createdDate < :endDate + """) List getStatusCountByAshaIdOfDefaultActivity( @Param("ashaId") Integer ashaId, @Param("startDate") Timestamp startDate, @@ -119,24 +119,23 @@ List getStatusCountByAshaIdOfDefaultActivity( @Query(""" -SELECT - SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), - SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), - SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), - SUM(CASE WHEN record.approvalStatus IN (101,105) THEN 1 ELSE 0 END) -FROM IncentiveActivityRecord record -WHERE record.ashaId = :ashaId -AND record.isClaimed = false -AND record.createdDate >= :startDate -AND record.createdDate < :endDate -""") + SELECT + SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END), + SUM(CASE WHEN record.approvalStatus IN (101,105) THEN 1 ELSE 0 END) + FROM IncentiveActivityRecord record + WHERE record.ashaId = :ashaId + AND record.isClaimed = false + AND record.createdDate >= :startDate + AND record.createdDate < :endDate + """) List getStatusUnclaimedCountByAshaId( @Param("ashaId") Integer ashaId, @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate); - @Query("SELECT COALESCE(SUM(record.amount), 0) " + "FROM IncentiveActivityRecord record " + "JOIN IncentiveActivity master ON record.activityId = master.id " + @@ -155,26 +154,26 @@ Long getTotalAmountByAsha( @Query(""" - SELECT COALESCE(SUM(record.amount), 0) - FROM IncentiveActivityRecord record - JOIN IncentiveActivity master ON record.activityId = master.id - WHERE record.ashaId = :ashaId - AND master.state = :stateCode - AND record.isClaimed = true - AND record.startDate >= :fromDate - AND record.endDate <= :toDate - AND ( - :approvalStatus = 0 - OR ( - :approvalStatus = 102 - AND record.approvalStatus IN (102, 105) - ) - OR ( - :approvalStatus <> 102 - AND record.approvalStatus = :approvalStatus - ) - ) -""") + SELECT COALESCE(SUM(record.amount), 0) + FROM IncentiveActivityRecord record + JOIN IncentiveActivity master ON record.activityId = master.id + WHERE record.ashaId = :ashaId + AND master.state = :stateCode + AND record.isClaimed = true + AND record.startDate >= :fromDate + AND record.endDate <= :toDate + AND ( + :approvalStatus = 0 + OR ( + :approvalStatus = 102 + AND record.approvalStatus IN (102, 105) + ) + OR ( + :approvalStatus <> 102 + AND record.approvalStatus = :approvalStatus + ) + ) + """) Long getTotalAmountByAshaANM( @Param("ashaId") Integer ashaId, @Param("fromDate") Timestamp fromDate, @@ -184,27 +183,27 @@ Long getTotalAmountByAshaANM( ); @Query(""" - SELECT COALESCE(SUM(record.amount), 0) - FROM IncentiveActivityRecord record - JOIN IncentiveActivity master ON record.activityId = master.id - WHERE record.ashaId = :ashaId - AND master.state = :stateCode - AND record.isClaimed = true - AND record.isDefaultActivity = false - AND record.startDate >= :fromDate - AND record.endDate <= :toDate - AND ( - :approvalStatus = 0 - OR ( - :approvalStatus = 102 - AND record.approvalStatus IN (102, 105) - ) - OR ( - :approvalStatus <> 102 - AND record.approvalStatus = :approvalStatus - ) - ) -""") + SELECT COALESCE(SUM(record.amount), 0) + FROM IncentiveActivityRecord record + JOIN IncentiveActivity master ON record.activityId = master.id + WHERE record.ashaId = :ashaId + AND master.state = :stateCode + AND record.isClaimed = true + AND record.isDefaultActivity = false + AND record.startDate >= :fromDate + AND record.endDate <= :toDate + AND ( + :approvalStatus = 0 + OR ( + :approvalStatus = 102 + AND record.approvalStatus IN (102, 105) + ) + OR ( + :approvalStatus <> 102 + AND record.approvalStatus = :approvalStatus + ) + ) + """) Long getTotalAmountByAshaANMbeforeClaimedHour( @Param("ashaId") Integer ashaId, @Param("fromDate") Timestamp fromDate, @@ -304,17 +303,17 @@ int updateApprovalStatusByIncentiveId( @Modifying @Transactional @Query(""" - UPDATE IncentiveActivityRecord iar - SET iar.approvalStatus = :approvalStatus, - iar.verifiedByUserId = :ashaSupervisorUserId, - iar.reason = NULL, - iar.otherReason = NULL, - iar.approvalDate = :approvalDate, - iar.verifiedByUserName = :ashaSupervisorUserName - WHERE iar.id IN :incentiveIds - AND iar.ashaId = :ashaId - AND iar.isClaimed = true - """) + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.reason = NULL, + iar.otherReason = NULL, + iar.approvalDate = :approvalDate, + iar.verifiedByUserName = :ashaSupervisorUserName + WHERE iar.id IN :incentiveIds + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + """) int updateApprovalStatusByIncentiveIds( @Param("incentiveIds") List incentiveIds, @Param("ashaId") Integer ashaId, @@ -328,19 +327,19 @@ int updateApprovalStatusByIncentiveIds( @Modifying @Transactional @Query(""" -UPDATE IncentiveActivityRecord iar -SET - iar.approvalStatus = :approvalStatus, - iar.verifiedByUserId = :ashaSupervisorUserId, - iar.verifiedByUserName = :ashaSupervisorUserName, - iar.approvalDate = :approvalDate, - iar.reason = NULL, - iar.otherReason = NULL -WHERE iar.ashaId = :ashaId -AND iar.isClaimed = true -AND iar.createdDate >= :startDate -AND iar.createdDate < :endDate -""") + UPDATE IncentiveActivityRecord iar + SET + iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.approvalDate = :approvalDate, + iar.reason = NULL, + iar.otherReason = NULL + WHERE iar.ashaId = :ashaId + AND iar.isClaimed = true + AND iar.createdDate >= :startDate + AND iar.createdDate < :endDate + """) int updateApprovalStatusByAshaAndDateRangeForDefaultActivity( @Param("ashaId") Integer ashaId, @Param("approvalStatus") Integer approvalStatus, @@ -354,18 +353,18 @@ int updateApprovalStatusByAshaAndDateRangeForDefaultActivity( @Modifying @Transactional @Query(""" -UPDATE IncentiveActivityRecord iar -SET - iar.approvalStatus = :approvalStatus, - iar.verifiedByUserId = :ashaSupervisorUserId, - iar.verifiedByUserName = :ashaSupervisorUserName, - iar.approvalDate = :approvalDate, - iar.reason = NULL, - iar.otherReason = NULL -WHERE iar.id = :incentiveId -AND iar.ashaId = :ashaId -AND iar.isClaimed = true -""") + UPDATE IncentiveActivityRecord iar + SET + iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.approvalDate = :approvalDate, + iar.reason = NULL, + iar.otherReason = NULL + WHERE iar.id = :incentiveId + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + """) int updateApprovalStatusByIncentiveIdForDefaultActivity( @Param("incentiveId") Long incentiveId, @Param("ashaId") Integer ashaId, @@ -378,18 +377,18 @@ int updateApprovalStatusByIncentiveIdForDefaultActivity( @Modifying @Transactional @Query(""" - UPDATE IncentiveActivityRecord iar - SET iar.approvalStatus = :approvalStatus, - iar.verifiedByUserId = :ashaSupervisorUserId, - iar.verifiedByUserName = :ashaSupervisorUserName, - iar.approvalDate = :approvalDate, - iar.reason = NULL, - iar.otherReason = NULL - WHERE iar.id IN :incentiveIds - AND iar.ashaId = :ashaId - AND iar.isClaimed = true - AND iar.isDefaultActivity = true - """) + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.approvalDate = :approvalDate, + iar.reason = NULL, + iar.otherReason = NULL + WHERE iar.id IN :incentiveIds + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + AND iar.isDefaultActivity = true + """) int updateApprovalStatusByIncentiveIdsForDefaultActivity( @Param("incentiveIds") List incentiveIds, @Param("ashaId") Integer ashaId, @@ -403,17 +402,17 @@ int updateApprovalStatusByIncentiveIdsForDefaultActivity( @Modifying @Transactional @Query(""" - UPDATE IncentiveActivityRecord iar - SET iar.approvalStatus = :approvalStatus, - iar.verifiedByUserId = :ashaSupervisorUserId, - iar.verifiedByUserName = :ashaSupervisorUserName, - iar.approvalDate = :approvalDate, - iar.reason = NULL, - iar.otherReason = NULL - WHERE iar.id IN :incentiveIds - AND iar.ashaId = :ashaId - AND iar.isClaimed = true - """) + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = :approvalStatus, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.approvalDate = :approvalDate, + iar.reason = NULL, + iar.otherReason = NULL + WHERE iar.id IN :incentiveIds + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + """) int updateApprovalStatusByIncentiveIdsForDefaultActivityForAnm( @Param("incentiveIds") List incentiveIds, @Param("ashaId") Integer ashaId, @@ -422,6 +421,7 @@ int updateApprovalStatusByIncentiveIdsForDefaultActivityForAnm( @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, @Param("ashaSupervisorUserName") String ashaSupervisorUserName ); + @Modifying @Transactional @Query("UPDATE IncentiveActivityRecord iar " @@ -470,17 +470,17 @@ int updateApprovalStatusByIdAndIncentiveId( @Modifying @Transactional @Query(""" - UPDATE IncentiveActivityRecord iar - SET iar.approvalStatus = :status, - iar.verifiedByUserId = :ashaSupervisorUserId, - iar.verifiedByUserName = :ashaSupervisorUserName, - iar.reason = :reason, - iar.otherReason = :otherReason, - iar.approvalDate = :approvalDate - WHERE iar.id IN :incentiveIds - AND iar.ashaId = :ashaId - AND iar.isClaimed = true - """) + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = :status, + iar.verifiedByUserId = :ashaSupervisorUserId, + iar.verifiedByUserName = :ashaSupervisorUserName, + iar.reason = :reason, + iar.otherReason = :otherReason, + iar.approvalDate = :approvalDate + WHERE iar.id IN :incentiveIds + AND iar.ashaId = :ashaId + AND iar.isClaimed = true + """) int updateApprovalStatusByIdsAndIncentiveIds( @Param("status") Integer status, @Param("ashaId") Integer ashaId, @@ -550,6 +550,7 @@ List getRecordsBySuperVisor( @Param("startDate") Timestamp startDate, @Param("endDate") Timestamp endDate, @Param("approvalStatus") Integer approvalStatus); + @Modifying @Transactional @Query("UPDATE IncentiveActivityRecord iar " @@ -568,21 +569,21 @@ int updateClaimStatusByAshaAndIncentiveIds( @Modifying(clearAutomatically = true, flushAutomatically = true) @Transactional @Query(""" - UPDATE IncentiveActivityRecord iar - SET iar.approvalStatus = 102, - iar.isClaimed = false, - iar.calimedDate = NULL, - iar.approvalDate = NULL, - iar.reason = NULL, - iar.otherReason = NULL, - iar.verifiedByUserId = NULL, - iar.verifiedByUserName = NULL, - iar.updatedDate = :updatedDate, - iar.updatedBy = :updatedBy - WHERE iar.approvalStatus = 103 - AND iar.isClaimed = true - AND iar.endDate < :currentMonthStart -""") + UPDATE IncentiveActivityRecord iar + SET iar.approvalStatus = 102, + iar.isClaimed = false, + iar.calimedDate = NULL, + iar.approvalDate = NULL, + iar.reason = NULL, + iar.otherReason = NULL, + iar.verifiedByUserId = NULL, + iar.verifiedByUserName = NULL, + iar.updatedDate = :updatedDate, + iar.updatedBy = :updatedBy + WHERE iar.approvalStatus = 103 + AND iar.isClaimed = true + AND iar.endDate < :currentMonthStart + """) int resetRejectedIncentivesForNewMonth( @Param("currentMonthStart") Timestamp currentMonthStart, @Param("updatedDate") Timestamp updatedDate, @@ -591,14 +592,10 @@ int resetRejectedIncentivesForNewMonth( @Query("SELECT r FROM IncentiveActivityRecord r " + "WHERE r.ashaId = :ashaId " + - "AND r.approvalStatus = :status " + - "AND r.startDate >= :start AND r.startDate < :end " + - "AND (r.isEligible = true OR r.isEligible IS NULL) " + - "AND (r.isClaimed = false OR r.isClaimed IS NULL)") + "AND r.approvalStatus = :status") List findApprovedForMonth( @Param("ashaId") Integer ashaId, - @Param("status") Integer status, - @Param("start") Timestamp start, - @Param("end") Timestamp end);} + @Param("status") Integer status); +} diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 2affddc01..2480f1faa 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1736,7 +1736,7 @@ public int updateApprovalStatus(Integer ashaId, if (incentiveIds == null || incentiveIds.trim().isEmpty()) { approvedRecords = incentiveRecordRepo .findApprovedForMonth( - ashaId, approvalStatus, startDate, endDate); + ashaId, approvalStatus); } else { List ids = Arrays.stream(incentiveIds.split(",")) .map(String::trim).filter(v -> !v.isEmpty()) From 6b317c8d47e5c79a14285605fc5bf9981535880b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 7 Oct 2026 11:45:42 +0530 Subject: [PATCH 203/237] fix approval staus issue --- .../impl/SupervisorDashboardServiceImpl.java | 108 +++++++++++++----- 1 file changed, 79 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 2480f1faa..90d108ea5 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1829,10 +1829,9 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, UserServiceRoleDTO supervisor, Integer supervisorUserId) { logger.info("========================================"); - logger.info("SSD Request Send to portal"); - logger.info("========================================"); + try { if (approvedRecords == null || approvedRecords.isEmpty()) { logger.info("No approved records, payment not triggered for asha {}", ashaId); @@ -1840,61 +1839,112 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, } LocalDate first = LocalDate.of(year, month, 1); + Period period = new Period(); - period.setStart(first.toString()); // 2026-01-01 - period.setEnd(first.withDayOfMonth(first.lengthOfMonth()).toString()); // 2026-01-31 + period.setStart(first.toString()); + period.setEnd(first.withDayOfMonth(first.lengthOfMonth()).toString()); VerifiedBy verifiedBy = new VerifiedBy(); - verifiedBy.setEmployeeId("NRHM-"+54374); + verifiedBy.setEmployeeId("NRHM-" + 54374); verifiedBy.setName(supervisor.getUserName()); - Map> byActivity = approvedRecords.stream() - .collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); + Map> byActivity = + approvedRecords.stream() + .collect(Collectors.groupingBy( + IncentiveActivityRecord::getActivityId + )); List items = new ArrayList<>(); + byActivity.forEach((activityId, recs) -> { + + var activityOpt = incentivesRepo.findById(activityId); + + // Activity not found -> skip + if (activityOpt.isEmpty()) { + logger.warn( + "Activity not found, skipping payment item. activityId={}", + activityId + ); + return; + } + + var activity = activityOpt.get(); + + // State Activity Code null -> skip + if (activity.getStateActivityCode() == null) { + logger.warn( + "State Activity Code is null, skipping payment item. activityId={}", + activityId + ); + return; + } + long count = recs.size(); + long total = recs.stream() .mapToLong(r -> r.getAmount() == null ? 0L : r.getAmount()) .sum(); PaymentItem item = new PaymentItem(); + item.setActivityCode( - incentivesRepo.findById(activityId) - .map(activity -> String.valueOf(activity.getStateActivityCode())) - .orElse(null) - ); item.setCount(String.valueOf(count)); + String.valueOf(activity.getStateActivityCode()) + ); + item.setCount(String.valueOf(count)); item.setIncentiveAmount(String.valueOf(total)); + items.add(item); }); + // Agar saare records ka activity code null tha + if (items.isEmpty()) { + logger.info( + "No valid payment items found for asha {}, payment not triggered", + ashaId + ); + return; + } + String timestamp = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")) .truncatedTo(ChronoUnit.SECONDS) - .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); // 2026-02-01T02:00:00+05:30 - if(employeeMasterRepo.findUserByUserID(ashaId)!=null){ - String empId = employeeMasterRepo.findUserByUserID(ashaId).getEmployeeID(); - if(empId!=null){ - PaymentRequest paymentRequest = new PaymentRequest( - UUID.randomUUID().toString(), - "AMRIT", - period, - String.valueOf(1857708), - timestamp, - verifiedBy, - items - ); - logger.info("PAYMENT REQUEST Payload: {}", new Gson().toJson(paymentRequest)); - paymentService.sendPaymentRequest(paymentRequest); - } + .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); - } + if (employeeMasterRepo.findUserByUserID(ashaId) != null) { + String empId = employeeMasterRepo + .findUserByUserID(ashaId) + .getEmployeeID(); + if (empId != null) { + PaymentRequest paymentRequest = new PaymentRequest( + UUID.randomUUID().toString(), + "AMRIT", + period, + String.valueOf(1857708), + timestamp, + verifiedBy, + items + ); + + logger.info( + "PAYMENT REQUEST Payload: {}", + new Gson().toJson(paymentRequest) + ); + + paymentService.sendPaymentRequest(paymentRequest); + } + } } catch (Exception e) { - logger.error("Payment request failed for asha {}: {}", ashaId, e.getMessage(), e); + logger.error( + "Payment request failed for asha {}: {}", + ashaId, + e.getMessage(), + e + ); } } private JSONObject buildEmptyIncentiveSummary() { From d4ec10dd36346979b4c682b0a24281b8388f61fd Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 7 Oct 2026 12:56:40 +0530 Subject: [PATCH 204/237] fix incentive activity code maping --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index 90d108ea5..d4f3e6b91 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1845,7 +1845,7 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, period.setEnd(first.withDayOfMonth(first.lengthOfMonth()).toString()); VerifiedBy verifiedBy = new VerifiedBy(); - verifiedBy.setEmployeeId("NRHM-" + 54374); + verifiedBy.setEmployeeId("NRHM-22547"); verifiedBy.setName(supervisor.getUserName()); Map> byActivity = From 0d85ac3b47748050a71ba9c07889118e7e8749b8 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 7 Oct 2026 13:10:50 +0530 Subject: [PATCH 205/237] fix mappping of asha with anm --- .../iemr/flw/service/impl/SupervisorDashboardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java index d4f3e6b91..11ab7f88e 100644 --- a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -1923,7 +1923,7 @@ public void triggerPayment(Integer ashaId, Integer month, Integer year, UUID.randomUUID().toString(), "AMRIT", period, - String.valueOf(1857708), + String.valueOf(30638), timestamp, verifiedBy, items From 72d60155ab932c78743c775c5dcdc1ea07b86442 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 9 Oct 2026 14:58:05 +0530 Subject: [PATCH 206/237] fix child vaccination get all data issue --- .../java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java | 5 ++--- .../java/com/iemr/flw/service/impl/ChildCareServiceImpl.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java b/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java index 99487cc2b..125f04d76 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java @@ -12,9 +12,8 @@ @Repository public interface ChildVaccinationRepo extends JpaRepository { - @Query(value = "SELECT cv FROM ChildVaccination cv WHERE cv.createdBy = :userId and cv.createdDate >= :fromDate and cv.createdDate <= :toDate") - List getChildVaccinationDetails(@Param("userId") String userId, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query(value = "SELECT cv FROM ChildVaccination cv WHERE cv.createdBy = :userId") + List getChildVaccinationDetails(@Param("userId") String userId); ChildVaccination findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName(Long benRegId, Timestamp createdDate, String vaccine); diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 46fac5ef3..ad944aa47 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -418,7 +418,7 @@ public List getChildVaccinationDetails(GetBenRequestHandler try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); List vaccinationDetails = - childVaccinationRepo.getChildVaccinationDetails(user, dto.getFromDate(), dto.getToDate()); + childVaccinationRepo.getChildVaccinationDetails(user); if (vaccinationDetails.isEmpty()) { return new ArrayList<>(); From 7b1e85549216ccfc9f948b74ffaacdf5d2079765 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 9 Oct 2026 15:20:28 +0530 Subject: [PATCH 207/237] fix child vaccination get all data issue --- .../impl/VillageLevelFormServiceImpl.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java index c21cc9a5e..ff1482e08 100644 --- a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java @@ -149,8 +149,15 @@ private Boolean saveVhncFormData(VhncFormDTO vhncFormDTO, Integer userID) { vhncForm.setFormType("VHNC"); vhncFormRepo.save(vhncForm); + if(vhncFormDTO.getVhncDate()!=null && !vhncFormDTO.getVhncDate().isEmpty()){ - checkVhncIncentive(vhncForm.getCreatedDate(),Math.toIntExact(vhncForm.getUserId())); + Timestamp timestamp = Timestamp.valueOf( + LocalDate.parse(vhncForm.getVhncDate(), DateTimeFormatter.ofPattern("dd-MM-yyyy")) + .atStartOfDay() + ); + + checkVhncIncentive(timestamp,Math.toIntExact(vhncForm.getUserId())); + } return true; } @@ -170,8 +177,17 @@ private Boolean savePhcForm(PhcReviewMeetingFormDTO dto, Integer userID) { phcReviewForm.setImage2(dto.getImage2()); phcReviewForm.setFormType("PHC"); phcReviewFormRepo.save(phcReviewForm); + if(dto.getPhcReviewDate()!=null && !dto.getPhcReviewDate().isEmpty()){ + + Timestamp timestamp = Timestamp.valueOf( + LocalDate.parse(phcReviewForm.getPhcReviewDate(), DateTimeFormatter.ofPattern("dd-MM-yyyy")) + .atStartOfDay() + ); + + checkPhcMeetingIncentive(timestamp,Math.toIntExact(phcReviewForm.getUserId())); + } + - checkPhcMeetingIncentive(phcReviewForm.getCreatedDate(),Math.toIntExact(phcReviewForm.getUserId())); return true; } @@ -278,8 +294,18 @@ private Boolean saveVhndFormData(VHNDFormDTO vhndFormDTO, Integer userID) { vhndForm.setFormType("VHND"); vhndRepo.save(vhndForm); + if (vhndFormDTO.getVhndDate() != null + && !vhndFormDTO.getVhndDate().isEmpty()) { - checkVhndIncentive(vhndForm.getCreatedDate(),vhndForm.getUserId()); + Timestamp timestamp = Timestamp.valueOf( + LocalDate.parse( + vhndFormDTO.getVhndDate(), + DateTimeFormatter.ofPattern("dd-MM-yyyy") + ).atStartOfDay() + ); + + checkVhndIncentive(timestamp, vhndForm.getUserId()); + } return true; From 43c1b501203ddc80ec1e3864181f785cedbf2fff Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Sun, 11 Oct 2026 15:08:05 +0530 Subject: [PATCH 208/237] fix sam visit sync issue --- .../java/com/iemr/flw/service/impl/ChildCareServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index ad944aa47..16b384002 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -583,6 +583,7 @@ public String saveSamDetails(List samRequest, Integer userId, String use samVisit.setVisitLabel(samDTO.getFields().getVisit_label()); samVisit.setWeightForHeightStatus(samDTO.getFields().getWeight_for_height_status()); samVisit.setIsChildReferredNrc(samDTO.getFields().getIs_child_referred_nrc()); + samVisit.setIsChildAdmittedNrc(samDTO.getFields().getIs_child_admitted_nrc()); samVisit.setNrcAdmissionDate(samDTO.getFields().getNrc_admission_date()); samVisit.setIsChildDischargedNrc(samDTO.getFields().getIs_child_discharged_nrc()); samVisit.setNrcDischargeDate(samDTO.getFields().getNrc_discharge_date()); From 158e6ea077ee35bf3c15a0a772647324e1e65044 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 12 Oct 2026 16:18:26 +0530 Subject: [PATCH 209/237] fix ors distrubution backdate issue --- .../com/iemr/flw/service/impl/CampaignServiceImpl.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java index f9c076327..a97898b15 100644 --- a/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java @@ -473,7 +473,6 @@ private void checkMonthlyPulseOrsDistribution(Integer ashaId,LocalDate startDate } private void addAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId,LocalDate startDate,LocalDate endDate) { - Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); Timestamp startOfMonth = Timestamp.valueOf(startDate.atStartOfDay()); Timestamp endOfMonth = Timestamp.valueOf(endDate.atStartOfDay()); @@ -490,11 +489,11 @@ private void addAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(incentiveActivity.getId()); - record.setCreatedDate(timestamp); + record.setCreatedDate(endOfMonth); record.setCreatedBy(userServiceRoleRepo.getUserNamedByUserId(ashaId)); - record.setStartDate(timestamp); - record.setEndDate(timestamp); - record.setUpdatedDate(timestamp); + record.setStartDate(endOfMonth); + record.setEndDate(endOfMonth); + record.setUpdatedDate(endOfMonth); record.setUpdatedBy(userServiceRoleRepo.getUserNamedByUserId(ashaId)); record.setBenId(0L); record.setAshaId(ashaId); From d432b1c06bce642bbc3fc8e83b03bbf27349a595 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 13 Oct 2026 15:02:22 +0530 Subject: [PATCH 210/237] ben id incentive fix issue --- .../service/impl/IncentiveServiceImpl.java | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 5fb04d0bc..3653f559b 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -267,16 +267,64 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { .collect(Collectors.toList()); Map benIdToNameMap = new HashMap<>(); + if (!benIdsToFetch.isEmpty()) { - List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); + + // Step 1: Fetch names using BeneficiaryId + List benDetails = + beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); + + Set foundBenIds = new HashSet<>(); + for (Object[] row : benDetails) { Long benId = ((Number) row[0]).longValue(); + String first = row[1] != null ? (String) row[1] : ""; String last = row[2] != null ? (String) row[2] : ""; + benIdToNameMap.put(benId, (first + " " + last).trim()); + foundBenIds.add(benId); } - } + // Step 2: Identify IDs for which names were not found + List unresolvedIds = benIdsToFetch.stream() + .filter(id -> !foundBenIds.contains(id)) + .distinct() + .toList(); + + if (!unresolvedIds.isEmpty()) { + + // Step 3: Resolve unresolved IDs as BenRegId + List mappings = + beneficiaryRepo.getBenIdsFromRegIds(unresolvedIds); + + Set resolvedBenIds = new HashSet<>(); + + for (Object[] row : mappings) { + if (row[1] != null) { + resolvedBenIds.add(((Number) row[1]).longValue()); + } + } + + // Step 4: Fetch names using resolved BeneficiaryIds + if (!resolvedBenIds.isEmpty()) { + + List resolvedDetails = + beneficiaryRepo.findBenNamesByBenIds( + new ArrayList<>(resolvedBenIds)); + + for (Object[] row : resolvedDetails) { + Long benId = ((Number) row[0]).longValue(); + + String first = row[1] != null ? (String) row[1] : ""; + String last = row[2] != null ? (String) row[2] : ""; + + benIdToNameMap.put( + benId, (first + " " + last).trim()); + } + } + } + } // NEW: Bulk fetch verifier (supervisor) roles — replaces N+1 userRepo.getUserRole() calls // Bulk fetch verifier (supervisor) roles — replaces N+1 userRepo.getUserRole() calls List verifierIds = entities.stream() From 51f30f535b6f809d7d84b46189aa5b89ddd11883 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 13 Oct 2026 15:37:44 +0530 Subject: [PATCH 211/237] ben id incentive fix issue --- .../service/impl/IncentiveServiceImpl.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 3653f559b..8e5ba07d1 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -267,10 +267,11 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { .collect(Collectors.toList()); Map benIdToNameMap = new HashMap<>(); + Map regIdToBenIdMap = new HashMap<>(); - if (!benIdsToFetch.isEmpty()) { + if (benIdsToFetch != null && !benIdsToFetch.isEmpty()) { - // Step 1: Fetch names using BeneficiaryId + // First, fetch names using BeneficiaryId List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); @@ -279,36 +280,38 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { for (Object[] row : benDetails) { Long benId = ((Number) row[0]).longValue(); - String first = row[1] != null ? (String) row[1] : ""; - String last = row[2] != null ? (String) row[2] : ""; + String first = row[1] != null ? row[1].toString() : ""; + String last = row[2] != null ? row[2].toString() : ""; benIdToNameMap.put(benId, (first + " " + last).trim()); foundBenIds.add(benId); } - // Step 2: Identify IDs for which names were not found + // IDs not found as BeneficiaryId List unresolvedIds = benIdsToFetch.stream() + .filter(Objects::nonNull) .filter(id -> !foundBenIds.contains(id)) .distinct() .toList(); if (!unresolvedIds.isEmpty()) { - // Step 3: Resolve unresolved IDs as BenRegId + // Resolve BenRegId -> BeneficiaryId List mappings = beneficiaryRepo.getBenIdsFromRegIds(unresolvedIds); Set resolvedBenIds = new HashSet<>(); for (Object[] row : mappings) { - if (row[1] != null) { - resolvedBenIds.add(((Number) row[1]).longValue()); - } + Long regId = ((Number) row[0]).longValue(); + Long benId = ((Number) row[1]).longValue(); + + regIdToBenIdMap.put(regId, benId); + resolvedBenIds.add(benId); } - // Step 4: Fetch names using resolved BeneficiaryIds + // Fetch names for resolved BeneficiaryIds if (!resolvedBenIds.isEmpty()) { - List resolvedDetails = beneficiaryRepo.findBenNamesByBenIds( new ArrayList<>(resolvedBenIds)); @@ -316,11 +319,10 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { for (Object[] row : resolvedDetails) { Long benId = ((Number) row[0]).longValue(); - String first = row[1] != null ? (String) row[1] : ""; - String last = row[2] != null ? (String) row[2] : ""; + String first = row[1] != null ? row[1].toString() : ""; + String last = row[2] != null ? row[2].toString() : ""; - benIdToNameMap.put( - benId, (first + " " + last).trim()); + benIdToNameMap.put(benId, (first + " " + last).trim()); } } } From 0d7c1e2d2ce830c8cd6bfc1e5a8106f88b3236e5 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 13 Oct 2026 15:51:08 +0530 Subject: [PATCH 212/237] ben id incentive fix issue --- .../flw/service/impl/IncentiveServiceImpl.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 8e5ba07d1..f8e72fdcf 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -346,12 +346,22 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { // Map entities to DTOs List dtos = entities.stream().map(entry -> { if (entry.getName() == null) { - if (entry.getBenId() != null && entry.getBenId() > 0) { - String name = benIdToNameMap.getOrDefault(entry.getBenId(), ""); + Long originalId = entry.getBenId(); + + if (originalId != null && originalId > 0) { + + Long actualBenId = regIdToBenIdMap.getOrDefault( + originalId, originalId); + + String name = benIdToNameMap.getOrDefault(actualBenId, ""); + + entry.setBenId(actualBenId); entry.setName(name); + if (isCG) { entry.setIsEligible(true); } + } else { entry.setName(""); } From 42e88b8ebcef1ad09f85c005fa6916c3970bf418 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 14 Oct 2026 11:30:40 +0530 Subject: [PATCH 213/237] drop column --- .../flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java | 6 ------ src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) 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 fa5f435fc..8354670ee 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java @@ -102,12 +102,6 @@ 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; diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java index e9369e76f..9353bcc1e 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java @@ -53,7 +53,7 @@ public class DiagnosticOrder { @Column(name = "error_message", columnDefinition = "TEXT") private String errorMessage; - @Column(name = "reason_for_refusal", columnDefinition = "TEXT") + @Column(name = "reason_to_close", columnDefinition = "TEXT") private String reasonForRefusal; @Column(name = "push_response_json", columnDefinition = "LONGTEXT") From eed530fa7e751a6bf07eb0c9b038d6b4699270cf Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 14 Oct 2026 11:31:25 +0530 Subject: [PATCH 214/237] drop column --- .../com/iemr/flw/service/impl/BeneficiaryServiceImpl.java | 6 ------ 1 file changed, 6 deletions(-) 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 396c79a2d..596517b78 100644 --- a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java @@ -363,12 +363,6 @@ private String getMappingsForAddressIDs(List addressLi if (benAddressOBJ.getPermPinCode() != null) benDetailsRMNCH_OBJ.setPinCode(benAddressOBJ.getPermPinCode()); - // 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 ca58b5bca5dd99dec54090a5388ee3f507e0467f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 14 Oct 2026 12:26:37 +0530 Subject: [PATCH 215/237] drop column --- .../flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java | 5 ----- .../iemr/flw/domain/identity/RMNCHHouseHoldDetails.java | 7 ------- .../com/iemr/flw/service/impl/BeneficiaryServiceImpl.java | 5 ----- 3 files changed, 17 deletions(-) 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 fa5f435fc..d4da36816 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java @@ -102,11 +102,6 @@ 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") 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 311abc7a6..c5cfa8524 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java @@ -329,13 +329,6 @@ public class RMNCHHouseHoldDetails { @Column(name = "isDeactivate") private Boolean isDeactivate; - @Expose - @Column(name = "gpsLatitude") - private Double gpsLatitude; - - @Expose - @Column(name = "gpsLongitude") - private Double gpsLongitude; @Expose @Column(name = "address") 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 396c79a2d..dda2bb9d1 100644 --- a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java @@ -363,11 +363,6 @@ private String getMappingsForAddressIDs(List addressLi if (benAddressOBJ.getPermPinCode() != null) benDetailsRMNCH_OBJ.setPinCode(benAddressOBJ.getPermPinCode()); - // 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())); // ----------------------------------------------------------------------------- From b57fe04bae9079b535673910f88355cb7fa76995 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 14 Oct 2026 12:36:22 +0530 Subject: [PATCH 216/237] drop column --- .../iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java | 3 --- src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) 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 d4da36816..d96ee5abc 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java @@ -107,9 +107,6 @@ public class RMNCHBeneficiaryDetailsRmnch { @Column(name = "digipin") private String digipin; - @Expose - @Column(name = "gpsTimestamp") - private Timestamp gpsTimestamp; @Expose @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java index e9369e76f..0be952bff 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java @@ -53,7 +53,7 @@ public class DiagnosticOrder { @Column(name = "error_message", columnDefinition = "TEXT") private String errorMessage; - @Column(name = "reason_for_refusal", columnDefinition = "TEXT") + @Column(name = "reason_for_close", columnDefinition = "TEXT") private String reasonForRefusal; @Column(name = "push_response_json", columnDefinition = "LONGTEXT") From a405caa35e32a79ee0150cbec9ce0099e96e21f7 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 14 Oct 2026 12:58:27 +0530 Subject: [PATCH 217/237] drop column --- src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java index 0be952bff..ae7dc52db 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java @@ -53,8 +53,8 @@ public class DiagnosticOrder { @Column(name = "error_message", columnDefinition = "TEXT") private String errorMessage; - @Column(name = "reason_for_close", columnDefinition = "TEXT") - private String reasonForRefusal; + @Column(name = "reason_to_close", columnDefinition = "TEXT") + private String reasonToClose; @Column(name = "push_response_json", columnDefinition = "LONGTEXT") private String pushResponseJson; From 0d8f317541d6db46c5145949c84fcbddc5cfbbea Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 14 Oct 2026 12:59:53 +0530 Subject: [PATCH 218/237] drop column --- .../iemr/flw/service/impl/DiagnosticOrderServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/DiagnosticOrderServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiagnosticOrderServiceImpl.java index 3e5ca60d6..1485843e6 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiagnosticOrderServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiagnosticOrderServiceImpl.java @@ -203,7 +203,7 @@ private DiagnosticOrder saveRefusedOrder(Long beneficiaryId, Long visitCode, Dia order.setPatientSex(patientSex); } order.setStatus(DiagnosticOrderStatus.REFUSED.name()); - order.setReasonForRefusal(reasonForRefusal); + order.setReasonToClose(reasonForRefusal); order.setErrorMessage(null); try { @@ -273,7 +273,7 @@ public DiagnosticOrderResultDto processResult(DiagnosticOrder order, DiagnosticP dto.setOrderType(order.getOrderType()); dto.setStatus(order.getStatus()); dto.setErrorMessage(order.getErrorMessage()); - dto.setReasonForRefusal(order.getReasonForRefusal()); + dto.setReasonForRefusal(order.getReasonToClose()); dto.setProviderStatus(result.getProviderStatus()); dto.setResultSummary(result.getResultSummary()); dto.setTbPresence(result.getTbPresence()); @@ -434,7 +434,7 @@ public DiagnosticOrderResultDto getOrderResult(Long beneficiaryId, String orderT dto.setExternalOrderId(order.getExternalOrderId()); dto.setStatus(order.getStatus()); dto.setErrorMessage(order.getErrorMessage()); - dto.setReasonForRefusal(order.getReasonForRefusal()); + dto.setReasonForRefusal(order.getReasonToClose()); diagnosticResultRepo.findByExternalOrderIdAndDeletedFalse(order.getExternalOrderId()).ifPresent(result -> { dto.setProviderStatus(result.getProviderStatus()); From f36e2d8d85f090d078859bad9dcd90c72174fefa Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 14 Oct 2026 15:15:53 +0530 Subject: [PATCH 219/237] fix mda incentive logic --- .../flw/service/impl/CampaignServiceImpl.java | 32 ++++++- .../impl/DiseaseControlServiceImpl.java | 85 +++++++++++++------ 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java index a97898b15..ffacf0a35 100644 --- a/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java @@ -459,7 +459,7 @@ private void checkMonthlyPulsePolioIncentive(Integer ashaId,LocalDate startDate, private void checkMonthlyFilariasisIncentive(Integer ashaId,LocalDate startDate,LocalDate endDate) { IncentiveActivity FILARIASIS_MEDICINE_DISTRIBUTION = incentivesRepo.findIncentiveMasterByNameAndGroup("FILARIASIS_MEDICINE_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); if (FILARIASIS_MEDICINE_DISTRIBUTION != null) { - addAshaIncentiveRecord(FILARIASIS_MEDICINE_DISTRIBUTION, ashaId,startDate,endDate); + addAshaIncentiveRecordMda(FILARIASIS_MEDICINE_DISTRIBUTION, ashaId,startDate,endDate); } } @@ -502,5 +502,35 @@ record = new IncentiveActivityRecord(); } } + + private void addAshaIncentiveRecordMda(IncentiveActivity incentiveActivity, Integer ashaId,LocalDate startDate,LocalDate endDate) { + + Timestamp startOfMonth = Timestamp.valueOf(startDate.atStartOfDay()); + Timestamp endOfMonth = Timestamp.valueOf(endDate.atStartOfDay()); + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + endOfMonth, + 0L,ashaId + + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(endOfMonth); + record.setCreatedBy(userServiceRoleRepo.getUserNamedByUserId(ashaId)); + record.setStartDate(endOfMonth); + record.setEndDate(endOfMonth); + record.setUpdatedDate(endOfMonth); + record.setUpdatedBy(userServiceRoleRepo.getUserNamedByUserId(ashaId)); + record.setBenId(0L); + record.setAshaId(ashaId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } + } diff --git a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java index 08caccd03..4cbfeb874 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java @@ -48,6 +48,7 @@ import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -352,41 +353,51 @@ private LeprosyFollowUp saveLeprosyFollowUpData(LeprosyFollowUpDTO data) { entity.setLastModDate( data.getLastModDate() != null ? data.getLastModDate() : new Timestamp(System.currentTimeMillis())); if(!leprosyFollowUpRepository.findByBenId(entity.getBenId()).isEmpty()){ - if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=6 && leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()<=12){ - Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForLeprosyPaucibacillaryConfirmed( - entity.getBenId(), - entity.getTreatmentEndDate(), - entity.getTreatmentEndDate(), - userId); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); + if(entity.getTypeOfLeprosy().equals("PB (Paucibacillary)")){ + if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=6 && leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()<=12){ + Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForLeprosyPaucibacillaryConfirmed( + entity.getBenId(), + entity.getTreatmentEndDate(), + entity.getTreatmentEndDate(), + userId); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } } } + } if(!leprosyFollowUpRepository.findByBenId(entity.getBenId()).isEmpty()){ - if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=12){ - Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); - IncentiveActivityRecord incentiveActivityRecord = - incentiveLogicService.incentiveForLeprosyMultibacillaryConfirmed( - entity.getBenId(), - entity.getTreatmentEndDate(), - entity.getTreatmentEndDate(), - userId); - - if (incentiveActivityRecord != null) { - logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", - incentiveActivityRecord.getId()); - } else { - logger.info("Incentive not created"); + if(entity.getTypeOfLeprosy().equals("MB (Multibacillary)")) { + if (entity.getTreatmentStartDate() != null && entity.getTreatmentEndDate() != null) { + if (isEligibleForIncentive(entity.getTreatmentStartDate(), entity.getTreatmentEndDate())) { + Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForLeprosyMultibacillaryConfirmed( + entity.getBenId(), + entity.getTreatmentEndDate(), + entity.getTreatmentEndDate(), + userId); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + } } } + + + } return entity; } @@ -401,6 +412,24 @@ public String saveLeprosyFollowUp(LeprosyFollowUpDTO dto) { } + public boolean isEligibleForIncentive(Date treatmentStartDate, Date endDate) { + + if (treatmentStartDate == null || endDate == null) { + return false; + } + + LocalDate start = treatmentStartDate.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate end = endDate.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + return end.isAfter(start.plusMonths(12)) + || end.isEqual(start.plusMonths(12)); + } + @Override public List getAllLeprosyData(String createdBy) { logger.info("Fetching leprosy data for createdBy: " + createdBy); From 058ecafbad59e2bec12bf3702cb488e3e7c3a3e2 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 15 Oct 2026 08:10:27 +0530 Subject: [PATCH 220/237] fix 10 hwc referal incentive issue --- .../flw/controller/IncentiveController.java | 10 +++- .../impl/TBConfirmedCaseServiceImpl.java | 47 ++++++++++++++++--- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/IncentiveController.java b/src/main/java/com/iemr/flw/controller/IncentiveController.java index 32a5c16fa..a251327d2 100644 --- a/src/main/java/com/iemr/flw/controller/IncentiveController.java +++ b/src/main/java/com/iemr/flw/controller/IncentiveController.java @@ -1,5 +1,6 @@ package com.iemr.flw.controller; +import com.google.gson.Gson; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.service.IncentiveService; @@ -31,6 +32,9 @@ public class IncentiveController { @Autowired IncentiveService incentiveService; + private static final Gson gson = new Gson(); + + @Autowired private JwtUtil jwtUtil; @@ -91,8 +95,10 @@ public String getAllIncentivesByUserId(@RequestBody GetBenRequestHandler request try { if (requestDTO != null) { - logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " - + requestDTO); + + logger.info("Request object with timestamp: {} | Request JSON: {}", + new Timestamp(System.currentTimeMillis()), + gson.toJson(requestDTO)); String s = incentiveService.getAllIncentivesByUserId(requestDTO); //logger.info("User Incentive:" + s); if (s != null) 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 1bbc5ec00..c9c4d1d6f 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -25,6 +25,7 @@ import java.sql.Timestamp; import java.time.LocalDate; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -149,12 +150,28 @@ private void checkIncentive(TBConfirmedCase entity){ if (isDrTb) { - incentiveLogicService.incentiveForTbFollowUpIsDrTb( - entity.getBenId(), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), - entity.getUserId() - ); + if("Shorter Regimen (9–12 Months)".equalsIgnoreCase(regimen)){ + if(isEligibleForIncentive(entity.getTreatmentStartDate(),entity.getExpectedTreatmentCompletionDate(),9)){ + incentiveLogicService.incentiveForTbFollowUpIsDrTb( + entity.getBenId(), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + entity.getUserId() + ); + } + + }else if("Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen)){ + if(isEligibleForIncentive(entity.getTreatmentStartDate(),entity.getExpectedTreatmentCompletionDate(),9)) { + + incentiveLogicService.incentiveForTbFollowUpIsDrTb( + entity.getBenId(), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + entity.getUserId() + ); + } + } + } else { incentiveLogicService.incentiveForTbFollowUp( entity.getBenId(), @@ -168,6 +185,24 @@ private void checkIncentive(TBConfirmedCase entity){ } } + public boolean isEligibleForIncentive(LocalDate treatmentStartDate, LocalDate endDate,Integer minMonth) { + + if (treatmentStartDate == null || endDate == null) { + return false; + } + + LocalDate start = treatmentStartDate.atStartOfDay() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate end = endDate.atStartOfDay() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + return end.isAfter(start.plusMonths(minMonth)) + || end.isEqual(start.plusMonths(minMonth)); + } + @Override public String getByBenId(Long benId, String authorisation) throws Exception { OutputResponse response = new OutputResponse(); From 1f5976656f156d7b1331af27b9e7b111e468ad95 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 15 Oct 2026 08:19:09 +0530 Subject: [PATCH 221/237] fix 10 hwc referal incentive issue --- .../service/impl/IncentiveServiceImpl.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index f8e72fdcf..b89cb137f 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -1,13 +1,11 @@ package com.iemr.flw.service.impl; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; -import com.iemr.flw.masterEnum.IncentiveApprovalStatus; import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; @@ -16,7 +14,6 @@ import com.iemr.flw.service.NotificationService; import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; -import jakarta.persistence.criteria.CriteriaBuilder; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -227,7 +224,7 @@ public String getAllIncentivesByUserId(GetBenRequestHandler request) { try { addIncentiveForIronTablets(request.getAshaId()); - incentiveOfNcdReferal(request.getAshaId(), request.getVillageID()); + incentiveOfNcdReferal(request.getAshaId(), request.getVillageID(),request); } catch (Exception e) { logger.error("Error in incentiveOfNcdReferal: ", e); } @@ -945,7 +942,7 @@ public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boo } } - private void incentiveOfNcdReferal(Integer ashaId, Integer stateId) { + private void incentiveOfNcdReferal(Integer ashaId, Integer stateId, GetBenRequestHandler request) { try { String userName = userRepo.getUserNamedByUserId(ashaId); String groupName = resolveGroupName(stateId); @@ -980,21 +977,23 @@ private void incentiveOfNcdReferal(Integer ashaId, Integer stateId) { } if (hwcReferralEnumeration != null) { - logger.info("hwcReferralEnumeration :" + hwcReferralEnumeration.getDescription()); + logger.info("hwcReferralEnumeration: {}", hwcReferralEnumeration.getDescription()); logger.info("userName={}", userName); - LocalDate now = LocalDate.now(); + LocalDate requestDate = request.getFromDate() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); Long referralCount = benReferDetailsRepo.countMonthlyReferrals( userName, - now.getMonthValue(), - now.getYear()); - - logger.info("referralCount :" + referralCount); + requestDate.getMonthValue(), + requestDate.getYear() + ); + logger.info("referralCount: {}", referralCount); if (referralCount >= 10) { - addHwcReferalAshaIncentiveRecord( hwcReferralEnumeration, ashaId, From 71dd24941265303f165e7bb6d20503b5b28f3fc3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 15 Oct 2026 12:36:08 +0530 Subject: [PATCH 222/237] fix 10 hwc referal incentive issue --- src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java | 4 ++-- .../com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java index 9cb356626..25a0b652a 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java @@ -51,8 +51,8 @@ public interface BenReferDetailsRepo extends JpaRepository Date: Thu, 15 Oct 2026 15:41:30 +0530 Subject: [PATCH 223/237] fix 10 hwc referal incentive issue --- .../com/iemr/flw/service/impl/MaternalHealthServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index c4dab2c9b..7cbab0af7 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -795,7 +795,7 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { } } - if (ect.getPncPeriod() == 42) { + if (ect.getPncPeriod() == 42 && !ect.getMotherDeath()) { IncentiveActivity highRiskPostpartumHealthCareActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); From dee7015416e0efb1bb23d2f4e672b9fe49766d3b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 16 Oct 2026 10:52:03 +0530 Subject: [PATCH 224/237] fix 10 hwc referal incentive issue --- .../iemr/flw/service/impl/MaternalHealthServiceImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 7cbab0af7..0e17c587e 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -795,7 +795,12 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { } } - if (ect.getPncPeriod() == 42 && !ect.getMotherDeath()) { + if (ect.getPncPeriod() == 42 + && !ect.getMotherDeath() + && ancVisitRepo.findByBenId(ect.getBenId()) + .stream() + .filter(ancVisit -> Integer.valueOf(7).equals(ancVisit.getAncVisit())) + .anyMatch(ancVisit -> Boolean.TRUE.equals(ancVisit.getIsHrpConfirmed()))) { IncentiveActivity highRiskPostpartumHealthCareActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); From 9639032e39fcce8ea9a1d3a1233d9666cdc22b10 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 16 Oct 2026 12:03:07 +0530 Subject: [PATCH 225/237] fix 10 hwc referal incentive issue --- .../impl/MaternalHealthServiceImpl.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 0e17c587e..c0ff4fcc1 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -799,17 +799,21 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { && !ect.getMotherDeath() && ancVisitRepo.findByBenId(ect.getBenId()) .stream() - .filter(ancVisit -> Integer.valueOf(7).equals(ancVisit.getAncVisit())) - .anyMatch(ancVisit -> Boolean.TRUE.equals(ancVisit.getIsHrpConfirmed()))) { + .filter(ancVisit -> ancVisit.getAncVisit() != null + && ancVisit.getAncVisit() >= 1 + && ancVisit.getAncVisit() <= 7) + .anyMatch(ancVisit -> + Boolean.TRUE.equals(ancVisit.getIsHrpConfirmed()))) { + IncentiveActivity highRiskPostpartumHealthCareActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); + incentivesRepo.findIncentiveMasterByNameAndGroup( + "HIGH_RISK_POSTPARTUM_HEALTH_CHECK", + GroupName.ACTIVITY.getDisplayName()); if (highRiskPostpartumHealthCareActivityCH != null) { - addIncenticeRecord(ect, userId, highRiskPostpartumHealthCareActivityCH); - + addIncenticeRecord(ect, userId, + highRiskPostpartumHealthCareActivityCH); } - - } if (ect.getPncPeriod() == 1 || ect.getPncPeriod() == 3 || ect.getPncPeriod() == 7) { if(ect.getContraceptionMethod()!=null){ From cf8e3aa2eb95fd4b2cc1f4d4e7cbb0f9cb159e4b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 16 Oct 2026 12:44:47 +0530 Subject: [PATCH 226/237] fix 10 hwc referal incentive issue --- .../iemr/flw/service/impl/MaternalHealthServiceImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index c0ff4fcc1..76f1ce31d 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -786,14 +786,16 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { if (ect.getMotherDangerSign() != null && !ect.getMotherDangerSign().isEmpty() - && ect.getPncPeriod() == 42) { + && ect.getPncPeriod() != null + && ect.getPncPeriod() >= 1 + && ect.getPncPeriod() <= 42) { + IncentiveActivity highRiskPostpartumCareActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); + if (highRiskPostpartumCareActivityCH != null) { addIncenticeRecord(ect, userId, highRiskPostpartumCareActivityCH); - } - } if (ect.getPncPeriod() == 42 && !ect.getMotherDeath() @@ -838,6 +840,7 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { } + @Transactional private void addIncenticeRecord(PNCVisit ect, Integer userId, IncentiveActivity antaraActivity) { From 8180cc812c9aafe1790238d4197a897fd599f298 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 16 Oct 2026 14:55:07 +0530 Subject: [PATCH 227/237] pnc mother incentive --- .../service/impl/ChildCareServiceImpl.java | 102 +++++++++++++++++- .../impl/MaternalHealthServiceImpl.java | 66 ++++++------ 2 files changed, 133 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 16b384002..d3974f1e4 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; +import com.iemr.flw.domain.identity.RMNCHBeneficiaryDetailsRmnch; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; @@ -16,6 +17,7 @@ import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; import jakarta.persistence.EntityNotFoundException; +import jakarta.transaction.Transactional; import org.aspectj.weaver.ast.Or; import org.modelmapper.ModelMapper; import org.slf4j.Logger; @@ -36,6 +38,7 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Service @@ -98,6 +101,7 @@ public class ChildCareServiceImpl implements ChildCareService { @Autowired private PNCVisitRepo pncVisitRepo; + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); @Override public String registerHBYC(List hbycDTOs) { @@ -1004,12 +1008,32 @@ private void checkAndAddHbncIncentives(List hbncVisits, Integer userI } if (stateCode.equals(StateCode.CG.getStateCode())) { - if (hbncVisit.getVisit_day().equals("42nd Day")) { - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.ACTIVITY.getDisplayName()); + if ("42nd Day".equals(hbncVisit.getVisit_day())) { + IncentiveActivity visitActivityCH = incentivesRepo + .findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.ACTIVITY.getDisplayName()); createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HBNC_0_42_DAYS"); + // 1. Child ka record + List childList = + beneficiaryRepo.findByBenficieryid(hbncVisit.getBeneficiaryId()); + + if (childList != null && !childList.isEmpty()) { + RMNCHBeneficiaryDetailsRmnch child = childList.get(childList.size() - 1); + + // 2. Same household se mother + RMNCHBeneficiaryDetailsRmnch mother = beneficiaryRepo + .findByHouseoldId(child.getHouseoldId()).stream() + .filter(b -> !"NewBorn".equalsIgnoreCase(b.getRegistrationType()) + && "Postnatal Mother".equalsIgnoreCase(b.getReproductiveStatus())) + .findFirst() + .orElse(null); + if (mother != null) { + generateHighRiskPostpartumIncentives(mother.getBenficieryid(), true, userId); + } + } } + } @@ -1019,6 +1043,80 @@ private void checkAndAddHbncIncentives(List hbncVisits, Integer userI } + private void generateHighRiskPostpartumIncentives(Long motherBenId, boolean childHbnc42Done, Integer userId) { + + if (!childHbnc42Done) return; + + List motherPnc = pncVisitRepo.findByBenId(motherBenId); + + PNCVisit visit42 = motherPnc.stream() + .filter(v -> Integer.valueOf(42).equals(v.getPncPeriod())) + .findFirst() + .orElse(null); + + if (visit42 == null) return; // mother ka PNC 42 abhi nahi hua + + boolean hasDangerSign = motherPnc.stream() + .anyMatch(v -> v.getMotherDangerSign() != null + && !v.getMotherDangerSign().isEmpty() + && v.getPncPeriod() != null + && v.getPncPeriod() >= 1 + && v.getPncPeriod() <= 42); + + if (hasDangerSign) { + IncentiveActivity act1 = incentivesRepo.findIncentiveMasterByNameAndGroup( + "HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); + if (act1 != null) { + addIncenticeRecord(visit42, userId, act1); // date 42 wale visit ki + } + } + + boolean motherAlive = !Boolean.TRUE.equals(visit42.getMotherDeath()); + + boolean hrpConfirmed = ancVisitRepo.findByBenId(motherBenId).stream() + .filter(a -> a.getAncVisit() != null && a.getAncVisit() >= 1 && a.getAncVisit() <= 7) + .anyMatch(a -> Boolean.TRUE.equals(a.getIsHrpConfirmed())); + + if (motherAlive && hrpConfirmed) { + IncentiveActivity act2 = incentivesRepo.findIncentiveMasterByNameAndGroup( + "HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); + if (act2 != null) { + addIncenticeRecord(visit42, userId, act2); + } + } + } + + @Transactional + private void addIncenticeRecord(PNCVisit ect, Integer userId, IncentiveActivity antaraActivity) { + + String lockKey = antaraActivity.getId() + "_" + ect.getBenId() + "_" + ect.getPncDate(); + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + + synchronized (lock) { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getPncDate(), ect.getBenId(),userId); + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(antaraActivity.getId()); + record.setCreatedDate(ect.getPncDate()); + record.setCreatedBy(ect.getCreatedBy()); + record.setStartDate(ect.getPncDate()); + record.setEndDate(ect.getPncDate()); + record.setUpdatedDate(ect.getPncDate()); + record.setUpdatedBy(ect.getCreatedBy()); + record.setBenId(ect.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(antaraActivity.getRate())); + recordRepo.save(record); + } + } + + lockMap.remove(lockKey, lock); + } + + private void checkAndAddIncentives(List vaccinationList) { String createdBy = vaccinationList.get(0).getCreatedBy(); diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 76f1ce31d..62534f071 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -784,39 +784,39 @@ private void checkAndAddAntaraIncentive(PNCVisit ect) { } - if (ect.getMotherDangerSign() != null - && !ect.getMotherDangerSign().isEmpty() - && ect.getPncPeriod() != null - && ect.getPncPeriod() >= 1 - && ect.getPncPeriod() <= 42) { - - IncentiveActivity highRiskPostpartumCareActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); - - if (highRiskPostpartumCareActivityCH != null) { - addIncenticeRecord(ect, userId, highRiskPostpartumCareActivityCH); - } - } - if (ect.getPncPeriod() == 42 - && !ect.getMotherDeath() - && ancVisitRepo.findByBenId(ect.getBenId()) - .stream() - .filter(ancVisit -> ancVisit.getAncVisit() != null - && ancVisit.getAncVisit() >= 1 - && ancVisit.getAncVisit() <= 7) - .anyMatch(ancVisit -> - Boolean.TRUE.equals(ancVisit.getIsHrpConfirmed()))) { - - IncentiveActivity highRiskPostpartumHealthCareActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup( - "HIGH_RISK_POSTPARTUM_HEALTH_CHECK", - GroupName.ACTIVITY.getDisplayName()); - - if (highRiskPostpartumHealthCareActivityCH != null) { - addIncenticeRecord(ect, userId, - highRiskPostpartumHealthCareActivityCH); - } - } +// if (ect.getMotherDangerSign() != null +// && !ect.getMotherDangerSign().isEmpty() +// && ect.getPncPeriod() != null +// && ect.getPncPeriod() >= 1 +// && ect.getPncPeriod() <= 42) { +// IncentiveActivity highRiskPostpartumCareActivityCH = +// incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); +// +// if (highRiskPostpartumCareActivityCH != null ) { +// addIncenticeRecord(ect, userId, highRiskPostpartumCareActivityCH); +// } +// +// } +// if (ect.getPncPeriod() == 42 +// && !ect.getMotherDeath() +// && ancVisitRepo.findByBenId(ect.getBenId()) +// .stream() +// .filter(ancVisit -> ancVisit.getAncVisit() != null +// && ancVisit.getAncVisit() >= 1 +// && ancVisit.getAncVisit() <= 7) +// .anyMatch(ancVisit -> +// Boolean.TRUE.equals(ancVisit.getIsHrpConfirmed()))) { +// +// IncentiveActivity highRiskPostpartumHealthCareActivityCH = +// incentivesRepo.findIncentiveMasterByNameAndGroup( +// "HIGH_RISK_POSTPARTUM_HEALTH_CHECK", +// GroupName.ACTIVITY.getDisplayName()); +// +// if (highRiskPostpartumHealthCareActivityCH != null) { +// addIncenticeRecord(ect, userId, +// highRiskPostpartumHealthCareActivityCH); +// } +// } if (ect.getPncPeriod() == 1 || ect.getPncPeriod() == 3 || ect.getPncPeriod() == 7) { if(ect.getContraceptionMethod()!=null){ if ((ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)") From f04cdb534bc6a009a34f74b3ba4c353f25eba971 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 16 Oct 2026 14:57:32 +0530 Subject: [PATCH 228/237] pnc mother incentive --- .../com/iemr/flw/service/impl/ChildCareServiceImpl.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index d3974f1e4..fffcdf3e0 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -290,9 +290,16 @@ public List getHBNCDetails(GetBenRequestHandler dto) { responseDTO.setFields(fields); result.add(responseDTO); + } page++; + try { + checkAndAddHbncIncentives(hbncVisits, dto.getAshaId()); + } catch (Exception e) { + logger.error("HBNC incentive check failed for ashaId {}: ", dto.getAshaId(), e); + } + }while (visitPage.hasNext()); } catch (Exception e) { From 3542d0eaec793ae68ae2a25d3d15f00c2875efb3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 16 Oct 2026 15:52:08 +0530 Subject: [PATCH 229/237] pnc mother incentive --- .../com/iemr/flw/service/impl/ChildCareServiceImpl.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index fffcdf3e0..adf47563a 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -294,12 +294,6 @@ public List getHBNCDetails(GetBenRequestHandler dto) { } page++; - try { - checkAndAddHbncIncentives(hbncVisits, dto.getAshaId()); - } catch (Exception e) { - logger.error("HBNC incentive check failed for ashaId {}: ", dto.getAshaId(), e); - } - }while (visitPage.hasNext()); } catch (Exception e) { @@ -1061,7 +1055,7 @@ private void generateHighRiskPostpartumIncentives(Long motherBenId, boolean chil .findFirst() .orElse(null); - if (visit42 == null) return; // mother ka PNC 42 abhi nahi hua + if (visit42 == null) return; boolean hasDangerSign = motherPnc.stream() .anyMatch(v -> v.getMotherDangerSign() != null From 68b637fe883cf57728c484972e6be5e37a6ea3e4 Mon Sep 17 00:00:00 2001 From: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Date: Thu, 22 Oct 2026 19:38:11 +0530 Subject: [PATCH 230/237] add DIAGNOSTIC_DOCUMENTS_STORAGE_ROOT in ci (#385) --- src/main/environment/common_ci.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index f2f3e0202..1bc41a0ea 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -79,4 +79,6 @@ diagnostic.emrlite.truenat.password=@env.DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD@ diagnostic.emrlite.token-ttl-seconds=@env.DIAGNOSTIC_EMRLITE_TOKEN_TTL_SECONDS@ diagnostic.emrlite.refresh-ttl-seconds=@env.DIAGNOSTIC_EMRLITE_REFRESH_TTL_SECONDS@ +diagnostic.documents.storage-root=@env.DIAGNOSTIC_DOCUMENTS_STORAGE_ROOT@ + From ab9e6a4bc33d0ab2e5d4a33e6bd59f96f3d91b67 Mon Sep 17 00:00:00 2001 From: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Date: Thu, 22 Oct 2026 19:42:57 +0530 Subject: [PATCH 231/237] update ci proprties (#386) --- src/main/environment/common_ci.properties | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 1bc41a0ea..2b3b04a03 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -80,5 +80,9 @@ diagnostic.emrlite.truenat.password=@env.DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD@ diagnostic.emrlite.token-ttl-seconds=@env.DIAGNOSTIC_EMRLITE_TOKEN_TTL_SECONDS@ diagnostic.emrlite.refresh-ttl-seconds=@env.DIAGNOSTIC_EMRLITE_REFRESH_TTL_SECONDS@ diagnostic.documents.storage-root=@env.DIAGNOSTIC_DOCUMENTS_STORAGE_ROOT@ +diagnostic.poll.xray.tick-ms=@env.DIAGNOSTIC_POLL_XRAY_TICK_MS@ +diagnostic.poll.truenat.tick-ms=@env.DIAGNOSTIC_POLL_TRUENAT_TICK_MS@ +# Daily cutoff (cron expression) after which all outstanding PENDING/IN_PROGRESS orders are marked EXPIRED +diagnostic.poll.expiry-cron=@env.DIAGNOSTIC_POLL_EXPIRY_CRON@ From e0c21c3f05f4a975df500b10553e7725565f6894 Mon Sep 17 00:00:00 2001 From: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Date: Thu, 22 Oct 2026 19:52:34 +0530 Subject: [PATCH 232/237] update ci proprties (#387) * update ci proprties * update ci proprties --- src/main/environment/common_ci.properties | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 2b3b04a03..862e4c314 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -85,4 +85,8 @@ diagnostic.poll.truenat.tick-ms=@env.DIAGNOSTIC_POLL_TRUENAT_TICK_MS@ # Daily cutoff (cron expression) after which all outstanding PENDING/IN_PROGRESS orders are marked EXPIRED diagnostic.poll.expiry-cron=@env.DIAGNOSTIC_POLL_EXPIRY_CRON@ +stoptb.enforce.vanid=@env.STOPTB_ENFORCE_VANID@ +# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup +stoptb.van.id=@env.STOPTB_VAN_ID@ + From 06ef2ec23e07073d32e83d5530a6a3040602f1c3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 23 Oct 2026 17:12:49 +0530 Subject: [PATCH 233/237] fix pre prod issue in release 3.11.0 --- .../impl/TBConfirmedCaseServiceImpl.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 2dc71c088..faf95f2fd 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -146,27 +146,27 @@ private void checkIncentive(TBConfirmedCase entity){ || "Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen); if (Boolean.TRUE.equals(entity.getTreatmentCompleted()) - && entity.getExpectedTreatmentCompletionDate() != null) { + && entity.getFollowUpDate() != null) { if (isDrTb) { if("Shorter Regimen (9–12 Months)".equalsIgnoreCase(regimen)){ - if(isEligibleForIncentive(entity.getTreatmentStartDate(),entity.getExpectedTreatmentCompletionDate(),9)){ + if ("cured".equalsIgnoreCase(entity.getTreatmentOutcome())) { incentiveLogicService.incentiveForTbFollowUpIsDrTb( entity.getBenId(), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), entity.getUserId() ); } }else if("Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen)){ - if(isEligibleForIncentive(entity.getTreatmentStartDate(),entity.getExpectedTreatmentCompletionDate(),18)) { + if ("cured".equalsIgnoreCase(entity.getTreatmentOutcome())) { incentiveLogicService.incentiveForTbFollowUpIsDrTb( entity.getBenId(), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), entity.getUserId() ); } @@ -175,8 +175,8 @@ private void checkIncentive(TBConfirmedCase entity){ } else { incentiveLogicService.incentiveForTbFollowUp( entity.getBenId(), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), entity.getUserId() ); From 35a3d7faf10e45d8ad3e5ca4c84f4023a536bdac Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 23 Oct 2026 17:15:41 +0530 Subject: [PATCH 234/237] fix pre prod issue in release 3.11.0 --- src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java index ae7dc52db..c6bf2695a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java @@ -53,7 +53,7 @@ public class DiagnosticOrder { @Column(name = "error_message", columnDefinition = "TEXT") private String errorMessage; - @Column(name = "reason_to_close", columnDefinition = "TEXT") + @Column(name = "reason_for_refusal", columnDefinition = "TEXT") private String reasonToClose; @Column(name = "push_response_json", columnDefinition = "LONGTEXT") From b2c8705b03653996c786ed18355423937e04cf74 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 27 Oct 2026 17:20:56 +0530 Subject: [PATCH 235/237] fix image store issue in village level froms --- src/main/java/com/iemr/flw/domain/iemr/AHDForm.java | 6 ++++-- .../java/com/iemr/flw/domain/iemr/DewormingForm.java | 6 ++++-- .../java/com/iemr/flw/domain/iemr/PHCReviewForm.java | 6 ++++-- src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java | 6 ++++-- src/main/java/com/iemr/flw/domain/iemr/VhncForm.java | 10 ++++++---- .../java/com/iemr/flw/dto/iemr/AhDMeetingFormDTO.java | 4 ++-- .../java/com/iemr/flw/dto/iemr/DewormingFormDTO.java | 4 ++-- .../com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java | 4 ++-- src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java | 4 ++-- src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java | 4 ++-- .../flw/service/impl/VillageLevelFormServiceImpl.java | 4 ++-- 11 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/AHDForm.java b/src/main/java/com/iemr/flw/domain/iemr/AHDForm.java index 808ba7827..f5565b3d6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AHDForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AHDForm.java @@ -26,11 +26,13 @@ public class AHDForm { @Column(name = "ahd_date") private String ahdDate; + @Lob @Column(name = "image1") - private String image1; + private byte[] image1; + @Lob @Column(name = "image2") - private String image2; + private byte[] image2; @Column(name = "user_id") private Long userId; diff --git a/src/main/java/com/iemr/flw/domain/iemr/DewormingForm.java b/src/main/java/com/iemr/flw/domain/iemr/DewormingForm.java index 1638e52e5..3df5156b2 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DewormingForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DewormingForm.java @@ -29,11 +29,13 @@ public class DewormingForm { @Column(name = "age_group") private Integer ageGroup; + @Lob @Column(name = "image1") - private String image1; + private byte[] image1; + @Lob @Column(name = "image2") - private String image2; + private byte[] image2; @Column(name = "user_id") private Long userId; diff --git a/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java b/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java index 42665c94c..9670f08f1 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java @@ -26,11 +26,13 @@ public class PHCReviewForm { @Column(name = "no_of_beneficiaries_attended") private Integer noOfBeneficiariesAttended; + @Lob @Column(name = "image1") - private String image1; + private byte[] image1; + @Lob @Column(name = "image2") - private String image2; + private byte[] image2; @Column(name = "user_id") private Long userId; diff --git a/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java b/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java index 2de5f6062..c940e8ea3 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java @@ -28,11 +28,13 @@ public class VHNDForm { @Column(name = "no_of_beneficiaries_attended") private Integer noOfBeneficiariesAttended; + @Lob @Column(name = "image1") - private String image1; + private byte[] image1; + @Lob @Column(name = "image2") - private String image2; + private byte[] image2; @Column(name = "form_type") private String formType; diff --git a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java index 858554daf..25bec9354 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java @@ -25,12 +25,14 @@ public class VhncForm { @Column(name = "no_of_beneficiaries_attended") private Integer noOfBeneficiariesAttended; - + + @Lob @Column(name = "image1") - private String image1; - + private byte[] image1; + + @Lob @Column(name = "image2") - private String image2; + private byte[] image2; @Column(name = "user_id") private Long userId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/AhDMeetingFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AhDMeetingFormDTO.java index 0ecc31be8..fdb6b9bbf 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/AhDMeetingFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/AhDMeetingFormDTO.java @@ -8,6 +8,6 @@ public class AhDMeetingFormDTO { private String mobilizedForAHD; private String ahdPlace; private String ahdDate; - private String image1; - private String image2; + private byte[] image1; + private byte[] image2; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/DewormingFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DewormingFormDTO.java index 3c3feb613..f7d6fa2bb 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DewormingFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DewormingFormDTO.java @@ -12,6 +12,6 @@ public class DewormingFormDTO { private String dewormingDate; private String dewormingLocation; private Integer ageGroup; - private String image1; - private String image2; + private byte[] image1; + private byte[] image2; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java index b08386c6e..4a88d0bd4 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java @@ -13,8 +13,8 @@ public class PhcReviewMeetingFormDTO { private String mitaninHistory; private String mitaninActivityCheckList; private Integer placeId; - private String image1; - private String image2; + private byte[] image1; + private byte[] image2; diff --git a/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java index aa99186a1..3ab437857 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java @@ -35,8 +35,8 @@ public class VHNDFormDTO { private String vhndDate; private String place; private Integer noOfBeneficiariesAttended; - private String image1; - private String image2; + private byte[] image1; + private byte[] image2; private Integer vhndPlaceId; private String pregnantWomenAnc; private String lactatingMothersPnc; diff --git a/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java index a2515b421..45f159689 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java @@ -32,8 +32,8 @@ public class VhncFormDTO { private String vhncDate; private String place; private Integer noOfBeneficiariesAttended; - private String image1; - private String image2; + private byte[] image1; + private byte[] image2; private String villageName; private Integer anm; private Integer aww; diff --git a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java index ff1482e08..52a33bc0a 100644 --- a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java @@ -233,8 +233,8 @@ private Boolean saveVhndFormData(VHNDFormDTO vhndFormDTO, Integer userID) { VHNDForm vhndForm = new VHNDForm(); vhndForm.setUserId(userID); vhndForm.setVhndDate(vhndFormDTO.getVhndDate()); - vhndForm.setImage2(vhndFormDTO.getImage2() != null ? vhndFormDTO.getImage2() : ""); - vhndForm.setImage1(vhndFormDTO.getImage1() != null ? vhndFormDTO.getImage1() : ""); + vhndForm.setImage2(vhndFormDTO.getImage2() != null ? vhndFormDTO.getImage2() : null); + vhndForm.setImage1(vhndFormDTO.getImage1() != null ? vhndFormDTO.getImage1() : null); vhndForm.setPlace(vhndFormDTO.getPlace() != null ? vhndFormDTO.getPlace() : ""); vhndForm.setNoOfBeneficiariesAttended( From 0f66c1a4256e06f2516f0b1afb7f0b07cb912e76 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 27 Oct 2026 17:24:36 +0530 Subject: [PATCH 236/237] fix image store issue in village level froms --- src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java index c6bf2695a..ae7dc52db 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java @@ -53,7 +53,7 @@ public class DiagnosticOrder { @Column(name = "error_message", columnDefinition = "TEXT") private String errorMessage; - @Column(name = "reason_for_refusal", columnDefinition = "TEXT") + @Column(name = "reason_to_close", columnDefinition = "TEXT") private String reasonToClose; @Column(name = "push_response_json", columnDefinition = "LONGTEXT") From 77f36c7e2f118262c57dc473f36896b24bf5bd6b Mon Sep 17 00:00:00 2001 From: sehjotsinghunthinkable Date: Mon, 2 Nov 2026 15:43:42 +0530 Subject: [PATCH 237/237] Merge to main release 3.12.0 (#397) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(user): append village ID into villageName so duplicate names are distinguishable Two different villages can legitimately share the same name (confirmed live: Nikshay village IDs 275135 and 275136 are both named "Sanapindapadar", under two different facilities in Boriguma block, Koraput). The mobile app's post-login village dropdown displays only villageName, so a user has no way to tell which entry is which - selecting the wrong one loads zero HH records for that village, since worklists filter by villageID, not by name. getUserDetail now appends the ID into each name segment, e.g. "Sanapindapadar,Sanapindapadar" + "275135,275136" becomes "Sanapindapadar (275135),Sanapindapadar (275136)". villageId and the response shape (two parallel comma-separated strings) are unchanged. Verified this requires zero mobile app changes: the village dropdown (ServiceLocationViewModel -> BindingUtils.setSpinnerItems) is a plain ArrayAdapter that displays villageName verbatim, and selection is by array position + villageId, not by matching name text. Co-Authored-By: Claude Sonnet 5 * chore: bump version to 3.8.4 Co-Authored-By: Claude Sonnet 5 * trace: add diagnostic logging to getBeneficiaryData for count-mismatch investigation Adds temporary [TRACE getBeneficiaryData] log lines to trace which caller/device is hitting the Stop TB worklist endpoint, how many pages/rows it gets back, and the household/non-household split actually sent to the client per call: - Controller: log real caller username (from JWT) + providerServiceMapID/ villageID/pageNo per request, instead of the previous useless default toString() of the request DTO. - Service: log totalCount/totalPage/addressIds per Stop TB page fetch. - Service: warn when getByAddressID() or getDetailsByRegID() return more than one row for a single address/beneficiary (both do .get(0) with no ORDER BY) — logs the distinct houseoldId values seen among duplicates, to confirm whether duplicate detail rows actually carry conflicting household links in production (not reproduced on the .198 demo DB, where duplicates found were exact clones with identical houseoldId). - Service: log a per-call summary of household-linked vs non-household counts in the response, for direct comparison against what each device's Home screen shows. Intended to be deployed to UAT StopTB and removed once the root cause of Nurse vs Registrar count mismatches (Achuthapuram, village 5821) is confirmed from real traffic. Co-Authored-By: Claude Sonnet 5 * fix: order duplicate-row lookups in getBeneficiaryData so .get(0) is deterministic and correct BenAddressId (i_beneficiarymapping.getByAddressID) and BenRegId (i_beneficiarydetails_rmnch.getDetailsByRegID) can both have more than one matching row, but the queries had no ORDER BY and the calling code in BeneficiaryServiceImpl just takes .get(0) — whichever row MySQL happened to return first, not necessarily the correct one. Confirmed live against the UAT StopTB database (Achuthapuram, village 5821): 36+ address IDs are shared between an old test-account registration and a real one, and some beneficiaries have duplicate detail rows where only the newer one has the household link recorded. Picking an arbitrary row instead of the latest one is why the Nurse and Registrar apps showed different Household/Non-Household counts for the same village. - getByAddressID: ORDER BY benMapId DESC, same "latest wins" convention already used in findByBenRegIdFromMapping (a5e57349). - getDetailsByRegID: ORDER BY beneficiaryDetails_RmnchId DESC. Verified locally against the real UAT DB: household/non-household split now matches the true numbers (computed from i_ben_flow_outreach, the actual source getBeneficiaryData's village worklist is built from) within a 1-record margin from an unrelated, pre-existing "mapping not available" skip. Does not touch the underlying duplicate rows themselves — those still need a data cleanup decision (which record to keep) separately from this code fix. Co-Authored-By: Claude Sonnet 5 * Revert "trace: add diagnostic logging to getBeneficiaryData for count-mismatch investigation" This reverts commit 911e2be1af9e009158e8139cc19a280a83317f27. * Dropping duplicate columns in table tb_stoptb_general_examination * Adding migration applier and removing column migration file * feat: add four new columns to TB screening form * feat: add dynamic form migrator and contact tracing migration * feat: change the flw-api version to 3.9.1 * feat: update Stop TB service implementation * feat: add dynamic form migrator with new form version creation * feat: refactored code * feat: changed flw-api version to 3.12.0 * chore: bump pom version to 3.9.1 Co-Authored-By: Claude Opus 5.5 * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * feat: stop-584 dynamic form backward compatibility changes * fix(diagnostic): stop the poll scheduler from nulling vanSerialNo pollOnce saved a stale copy of the order loaded before createAndPushOrder's updateVanSerialNo() ran, writing vanSerialNo back to NULL. MMU sync keys tb_diagnostic_order by vanSerialNo, so those rows could never sync and the Stop TB sync group stayed partial. - refill vanSerialNo after the scheduler's save in pollOnce - mark vanSerialNo updatable=false on the diagnostic entities so entity saves can no longer overwrite it (updateVanSerialNo still sets it) Co-Authored-By: Claude Opus 5.5 * fix(diagnostic): stamp vanSerialNo right after the order is first saved Fill vanSerialNo before the (possibly slow) EMR Lite push instead of only after it, so a crash or restart mid-push can't leave the order without its sync key. Same value (= id); no change to status, push or response. Co-Authored-By: Claude Opus 5.5 * feat: stop-542 extra fields consumer changes * Revert "feat: stop-542 extra fields consumer changes" This reverts commit 50dc8bad084561fdebfe35b9f8f30627ddbe6a10. * feat: stop-542 extra fields consumer changes * feat(stoptb): save OPD prescription to standard tables and dispense stock Same endpoint stoptb/nurse/generalOpd/save. When the app sends the new fields (submissionId, chiefComplaints[], prescription.drugs[] with drugID and qtyPrescribed) the save writes t_benchiefcomplaint, t_prescription, t_prescribeddrug, t_patientissue and t_itemstockexit and reduces t_itemstockentry from the van's store, like TM and Inventory-API. One transaction: insufficient stock rejects the whole submit. submissionId makes retries safe. Old payload behaves as before. The configured stoptb.van.id is the source of truth; a different vanID from the app is rejected. Parking place and store are read from m_van. Co-Authored-By: Claude Opus 5.5 * fix(stoptb): close dispensing gaps found in review - Always use stoptb.van.id; a vanID sent by the app is ignored (logged). - Reduced batch gets Processed='N' so the new quantity uploads to central; removed chief complaints are re-sent the same way. - Batches with no expiry date are usable, as in v_drugforprescription. - Drug must be mapped to the store on its own service line, same join as the drug list, so the save accepts exactly what the list shows. - Patient name, age and gender filled on t_patientissue for the Inventory dispense screen. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): General OPD on AMRIT standard tables only - New payload (chiefComplaints[] / prescription.drugs[]) no longer writes tb_stoptb_general_opd; complaints, prescription and dispensing live only in t_benchiefcomplaint, t_prescription, t_prescribeddrug, t_patientissue, t_itemstockexit. - generalOpd/getAll reads the standard tables first and falls back to tb_stoptb_general_opd only for older visits that exist only there. Response fields and formats are unchanged for the app. - Old app payload keeps its current behaviour. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): calculate tablet/capsule quantity when the app sends none qtyPrescribed from the app is used as is. When it is missing, for tablets and capsules (MMU's prescription screen asks quantity only for other forms) it is doses per day x days from frequency and duration; Single/Stat dose = 1, Once in a Week = 1 per 7 days. SOS or other forms without a quantity are rejected. The calculated value is saved in t_prescribeddrug.QtyPrescribed and dispensed. Co-Authored-By: Claude Opus 5.5 * fix(stoptb): OPD save validations from final review - chiefComplaintID is required for each chief complaint (getAll and reports identify standard-table records by it). - prescription.instruction is saved in t_prescription even when no drug is given, as MMU does for the visit instruction. - providerServiceMapID and createdBy give a clear error when missing instead of a database error. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): default quantity 1 for non-tablet medicines when the app sends none Co-Authored-By: Claude Opus 5.5 * feat(stoptb): getAll drugs list with form; SOS quantity default - generalOpd/getAll returns a "drugs" list per record (drugID, drugName, itemFormID, drugForm, dose, frequency, duration, durationUnit, qtyPrescribed, instructions) from t_prescribeddrug, so a saved prescription can be shown with form and quantity. Existing fields are unchanged; old free-text records return an empty list. - SOS tablets/capsules without a quantity: 1 per day of duration (1 when no duration) instead of rejecting the save. Co-Authored-By: Claude Opus 5.5 * updated version to 3.9.2 * Removing gpsLatitude and gpsLongitude, and setting values into latitude and longitude * Adding locking for multiple order creation * Adding locking for multiple order creation * fix(stoptb): fill missing service line on the day's visit TB suspected / confirmed / diagnostic saves create the visit with ProviderServiceMapID null. When one of them syncs before TB screening or OPD, the visit keeps null and getAll (filters by psm) skips it. A later save that has a service line now fills it in. Co-Authored-By: Claude Opus 5.5 * Adding locking for multiple order creation * fix(stoptb): MMU dose-based quantity; no batch re-upload after dispense - Quantity for tablets uses the dose like MMU (Half Tab 0.5, One Tab 1, One & Half Tab 1.5, Two Tabs 2 per intake), rounded up. No dose sent = one tablet, so today's results are unchanged. - Dispense no longer marks the stock batch Processed='N'. Central gets the stock-out rows (standard MMU); re-sending a batch could insert a duplicate batch on central. Co-Authored-By: Claude Opus 5.5 * fix(stoptb): send the batch's new stock to central after an OPD dispense The dispensed batch is marked Processed='N' again so the next upload updates central's copy (matched by VanSerialNo + store, now kept by central MMU-API). Co-Authored-By: Claude Opus 5.5 * feat(stoptb): save OPD prescription to standard tables and dispense stock Same endpoint stoptb/nurse/generalOpd/save. When the app sends the new fields (submissionId, chiefComplaints[], prescription.drugs[] with drugID and qtyPrescribed) the save writes t_benchiefcomplaint, t_prescription, t_prescribeddrug, t_patientissue and t_itemstockexit and reduces t_itemstockentry from the van's store, like TM and Inventory-API. One transaction: insufficient stock rejects the whole submit. submissionId makes retries safe. Old payload behaves as before. The configured stoptb.van.id is the source of truth; a different vanID from the app is rejected. Parking place and store are read from m_van. Co-Authored-By: Claude Opus 5.5 * fix(stoptb): close dispensing gaps found in review - Always use stoptb.van.id; a vanID sent by the app is ignored (logged). - Reduced batch gets Processed='N' so the new quantity uploads to central; removed chief complaints are re-sent the same way. - Batches with no expiry date are usable, as in v_drugforprescription. - Drug must be mapped to the store on its own service line, same join as the drug list, so the save accepts exactly what the list shows. - Patient name, age and gender filled on t_patientissue for the Inventory dispense screen. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): General OPD on AMRIT standard tables only - New payload (chiefComplaints[] / prescription.drugs[]) no longer writes tb_stoptb_general_opd; complaints, prescription and dispensing live only in t_benchiefcomplaint, t_prescription, t_prescribeddrug, t_patientissue, t_itemstockexit. - generalOpd/getAll reads the standard tables first and falls back to tb_stoptb_general_opd only for older visits that exist only there. Response fields and formats are unchanged for the app. - Old app payload keeps its current behaviour. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): calculate tablet/capsule quantity when the app sends none qtyPrescribed from the app is used as is. When it is missing, for tablets and capsules (MMU's prescription screen asks quantity only for other forms) it is doses per day x days from frequency and duration; Single/Stat dose = 1, Once in a Week = 1 per 7 days. SOS or other forms without a quantity are rejected. The calculated value is saved in t_prescribeddrug.QtyPrescribed and dispensed. Co-Authored-By: Claude Opus 5.5 * fix(stoptb): OPD save validations from final review - chiefComplaintID is required for each chief complaint (getAll and reports identify standard-table records by it). - prescription.instruction is saved in t_prescription even when no drug is given, as MMU does for the visit instruction. - providerServiceMapID and createdBy give a clear error when missing instead of a database error. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): default quantity 1 for non-tablet medicines when the app sends none Co-Authored-By: Claude Opus 5.5 * feat(stoptb): getAll drugs list with form; SOS quantity default - generalOpd/getAll returns a "drugs" list per record (drugID, drugName, itemFormID, drugForm, dose, frequency, duration, durationUnit, qtyPrescribed, instructions) from t_prescribeddrug, so a saved prescription can be shown with form and quantity. Existing fields are unchanged; old free-text records return an empty list. - SOS tablets/capsules without a quantity: 1 per day of duration (1 when no duration) instead of rejecting the save. Co-Authored-By: Claude Opus 5.5 * Dropping duplicate columns in table tb_stoptb_general_examination * Adding migration applier and removing column migration file * feat: add dynamic form migrator and contact tracing migration * feat: change the flw-api version to 3.9.1 * feat: update Stop TB service implementation * feat: add dynamic form migrator with new form version creation * feat: refactored code * feat: changed flw-api version to 3.12.0 * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * Updated the device integration according to updated workflow * feat: stop-584 dynamic form backward compatibility changes * feat: stop-542 extra fields consumer changes * Revert "feat: stop-542 extra fields consumer changes" This reverts commit 50dc8bad084561fdebfe35b9f8f30627ddbe6a10. * feat: stop-542 extra fields consumer changes * fix(stoptb): fill missing service line on the day's visit TB suspected / confirmed / diagnostic saves create the visit with ProviderServiceMapID null. When one of them syncs before TB screening or OPD, the visit keeps null and getAll (filters by psm) skips it. A later save that has a service line now fills it in. Co-Authored-By: Claude Opus 5.5 * Removing gpsLatitude and gpsLongitude, and setting values into latitude and longitude * Adding locking for multiple order creation * Adding locking for multiple order creation * fix(stoptb): MMU dose-based quantity; no batch re-upload after dispense - Quantity for tablets uses the dose like MMU (Half Tab 0.5, One Tab 1, One & Half Tab 1.5, Two Tabs 2 per intake), rounded up. No dose sent = one tablet, so today's results are unchanged. - Dispense no longer marks the stock batch Processed='N'. Central gets the stock-out rows (standard MMU); re-sending a batch could insert a duplicate batch on central. Co-Authored-By: Claude Opus 5.5 * fix(stoptb): send the batch's new stock to central after an OPD dispense The dispensed batch is marked Processed='N' again so the next upload updates central's copy (matched by VanSerialNo + store, now kept by central MMU-API). Co-Authored-By: Claude Opus 5.5 * Changes for STOP-711 * Making changes for STOP-735 * feat(stoptb): /stoptb/sync/changes feed on the hub change log One endpoint replaces the 15+ getAll calls a STOP-TB pull makes. With no token it pages through everything in the requested villages (keyset, type by type, beneficiaries first); after that it returns only records with t_sync_change_log lines after the tablet's token, in their current state, deduplicated, with deletes. Tokens carry the hub's server_uuid, so a token from another hub or older than the log's retention starts a fresh snapshot. Records keep the exact JSON each existing endpoint returns, via by-id variants of the existing builders (beneficiary, screening, examination, OPD, diagnostics, suspected, confirmed, form responses, diagnostic orders), so the app reuses its parsers. The feed is served only where the change log exists and every source table has its triggers (checked on the hub); elsewhere it answers {supported:false} and the app keeps the full pull. StopTBSyncCoverageTest fails when a mapped table is neither synced nor listed as deliberately not synced. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): let the app choose which record types the changes feed returns Co-Authored-By: Claude Opus 5.5 * fix(stoptb): treat t_prescription as a source of the OPD record The OPD record's notes come from the visit's latest t_prescription instruction. A remarks-only save writes only that table, so without it in the list the change log missed the edit and tablets kept the old note. Paired with the t_prescription trigger in the AMRIT-DB hub migration. Co-Authored-By: Claude Opus 5.5 * fix(stoptb): bound beneficiaries per feed page and bind tokens to record types - A page carries at most 25 beneficiary records. Each costs several identity lookups and a FHIR call, so 200-500 per page could outlast the tablet's HTTP timeout. In a snapshot the token resumes after the last one sent; in a delta the row list stops before the one over the cap and the token resumes from the last row kept, so nothing is skipped. - Tokens carry the set of record types they were issued for. A request for a different set starts a new snapshot instead of missing the newly requested types' existing records. Co-Authored-By: Claude Opus 5.5 * docs(stoptb): the change log now comes from AMRIT-DB main migrations V132 / V32 Co-Authored-By: Claude Opus 5.5 * Efficency on Stoptbapp (#394) * perf(worklist): batch per-page lookups in getBeneficiaryData Load mapping, details, account, image, address, contact, beneficiary ID, rmnch, born-birth, household, flow, anthropometry, vitals and user lookups once per page instead of once per beneficiary. Read ABHA from m_benhealthidmapping/t_healthid directly instead of calling FHIR-API per beneficiary. Falls back to the existing per-row queries if the batch load fails or a single-result lookup finds more than one row. Co-Authored-By: Claude Opus 5.5 * perf(worklist): page size 50 and per-page timing log door-to-door-page-size 10 -> 50 so a village pull needs 5x fewer requests. Log one [WORKLIST-TIMING] line per Stop TB village worklist page with the time spent in count, ids, address, prefetch, build and JSON. Co-Authored-By: Claude Opus 5.5 * perf(worklist): index-only count and page query; per-request timing log Count village flow rows without the mapping join, and page with a deferred join so OFFSET skips on idx_flow_psm_village_reg only and just the page's rows are joined to the mapping. Ties on registrationDate are ordered by ben_flow_id so a page boundary cannot skip or repeat a beneficiary. An in-range page with no mapped rows returns an empty page instead of "No record found". Add ApiTimingFilter: one [API-TIMING] line per request with method, path, status and time. Co-Authored-By: Claude Opus 5.5 * perf(stoptb): faster TB suspected and Stop TB getAll responses TB suspected getAll looked up the full user detail (role + facility queries) for every confirmed row only to read the state for the incentive check; look it up once per user. The incentive rules and calls are unchanged. Stop TB general exam, screening, OPD and diagnostics getAll built the JSON text, parsed it back and wrote it again; build the tree once via OutputResponse.setResponse(JsonElement). Load those rows read-only. Responses are byte-identical to before (Stop TB getAlls and the FLW app worklist/suspected paths compared on the 3307 test DB). Co-Authored-By: Claude Opus 5.5 * perf(stoptb): one-query diagnostic status summary; leaner suspected and OPD lists Diagnostic status summary read each beneficiary's latest order five times, once per status bucket; read beneficiaryId + status once and bucket in Java with the same status groups (case-insensitive, like the database comparison). Bucket contents are unchanged; order inside a bucket was never fixed by the query. TB suspected getAll copies the DTO fields directly instead of ModelMapper per row, and its village subquery hints idx_flow_psm_village_reg (MySQL ignores the hint where that index is absent). Standard OPD records for a village start from the village's beneficiaries instead of every visit of the PSM; the same visits match. Co-Authored-By: Claude Opus 5.5 * perf(stoptb): keep TB suspected speed-up on the Stop TB village path only Restore IncentiveLogicService/IncentiveLogicImpl to their original code and run the FLW (ashaId) path of TB suspected getAll exactly as before. The Stop TB village path reads each user's state once and calls the unchanged incentiveForTbSuspected only for CG users, the only state where it acts. Co-Authored-By: Claude Opus 5.5 * perf(worklist): restore original village count and page queries The index-only count also counted flow rows that have no i_beneficiarymapping row (423 on the reference DB, mostly PSM 1725), so villages with such rows got extra or empty pages and a fully unmapped village got an empty success instead of "No record found". Put countVillageWorklist, getVillageWorklistAddressIds and the empty-page handling back to the release-3.12.0 behaviour. The batch loader, page size and timing logs stay. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 * fix(stoptb): never move the feed past a change whose transaction is still open The safe point was the newest log line older than 5 s. seq is taken at insert, not at commit, so a transaction open longer than that could commit a lower seq after the feed had moved past it, and tablets would miss the change. The safe point is now below the oldest open transaction (information_schema.innodb_trx), minus the same 5 s margin; without the PROCESS privilege it falls back to the fixed lag and logs a warning once. Reproduced on MySQL 8.0: with A open holding seq 5 and B committed at seq 6, the old rule returned 6 (skipping 5); the new one returns 0 until A commits, then 6. Co-Authored-By: Claude Opus 5.5 * fix(diagnostics): polls that change nothing don't rewrite the order or result Every pending order was saved on every poll (every ~35 s): processed reset to 'N' so MMU re-uploaded it, and the change-log trigger re-sent it to every tablet. Now, when the vendor reports the same status, error, provider order id and result fields, only last_polled_at (and the retry count) is updated; a repeated poll error is recorded the same way. Real changes are saved as before. Pairs with AMRIT-DB V134 (PSMRI/AMRIT-DB#227). Co-Authored-By: Claude Opus 5.5 * feat(stoptb): send a beneficiary's older records when they come into scope AMRIT-DB V134 logs flow-table scope changes (new flow row, village / service / deleted change) with op 'S'. When a delta page has such a line for a beneficiary, the feed now also sends that beneficiary's existing records of every requested type: they were logged before the beneficiary was in the tablet's villages, so they never passed the scope check and the token had already moved past them. Each type's query for this is derived from its snapshot query (village scope swapped for the given BenRegIds, paging dropped); StopTBSyncTypeTest checks every one. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): changes feed only serves the user's own villages, all of them by default - The feed reads the user from the JwtToken header (required) and their services and villages from every active m_userservicerolemapping row. A service or village the user isn't mapped to is rejected; no villageIds means all of the user's villages for that service. Cached 5 minutes per user. - Tokens carry a hash of the service and village list, so a different scope starts a new snapshot instead of continuing from another scope's position. - getUserDetail no longer takes whichever mapping row came first: it uses the STOP-TB (Nikshay) row when there is one, merges villages across all rows for that service, and fails clearly when the user has no mapping instead of IndexOutOfBounds. UserSyncScopeTest covers merging, defaults and rejection; SyncTokenTest the new token. Co-Authored-By: Claude Opus 5.5 * fix(diagnostic): don't treat a failed result update as a lost race processResult caught every DataIntegrityViolationException on the result save as a lost insert race and went on to mark the order COMPLETED. When the save of an existing result failed (V134 trigger NULL row_pk), the order completed with its result still PENDING. Only a first insert can race; rethrow otherwise so the order is left as it was. Co-Authored-By: Claude Opus 5.5 * feat(stoptb): save OPD prescription without dispensing by default (#395) Inventory is not part of this release, so the Stop TB OPD save no longer checks the camp store or stock, writes no patient issue and leaves stock unchanged. Drugs from the app's own list are saved as sent (DrugID, name, form, frequency, duration, instructions); quantity is worked out when the app sends 0. A new save for the visit replaces its earlier prescription, so an edit or retry leaves one copy. The existing dispensing path is kept behind stoptb.dispense.enabled (default false, no config needed) for the release that brings inventory. Co-authored-by: Claude Opus 5.5 --------- Co-authored-by: vishwab1 Co-authored-by: Claude Sonnet 5 Co-authored-by: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Co-authored-by: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Co-authored-by: chetansaroya Co-authored-by: Mithun James <1007084+drtechie@users.noreply.github.com> --- pom.xml | 2 +- src/main/environment/common_ci.properties | 2 + src/main/environment/common_docker.properties | 2 + .../environment/common_example.properties | 77 +- .../controller/DiagnosticOrderController.java | 20 +- .../flw/controller/DynamicFormController.java | 9 + .../iemr/flw/controller/StopTBController.java | 13 +- .../flw/controller/StopTBSyncController.java | 77 ++ .../RMNCHBeneficiaryDetailsRmnch.java | 4 +- .../flw/domain/iemr/DiagnosticDocument.java | 2 +- .../iemr/flw/domain/iemr/DiagnosticOrder.java | 11 +- .../domain/iemr/DiagnosticProviderToken.java | 2 +- .../flw/domain/iemr/DiagnosticResult.java | 2 +- .../domain/iemr/DynamicFormMigrationLog.java | 53 ++ .../com/iemr/flw/domain/iemr/FormSection.java | 5 + .../com/iemr/flw/domain/iemr/FormVersion.java | 5 + .../iemr/flw/domain/iemr/OptionCondition.java | 4 + .../iemr/flw/domain/iemr/QuestionOption.java | 18 + .../flw/domain/iemr/QuestionValidation.java | 4 + .../iemr/flw/domain/iemr/SectionQuestion.java | 5 + .../flw/domain/iemr/StopTBDiagnostics.java | 2 +- .../com/iemr/flw/domain/iemr/TBScreening.java | 27 +- .../flw/dto/DiagnosticOrderRequestDto.java | 5 +- .../flw/dto/DiagnosticOrderResultDto.java | 2 +- .../dto/DiagnosticOrderStatusSummaryDto.java | 3 +- .../dto/ManualDiagnosticResultRequestDto.java | 4 +- .../com/iemr/flw/dto/iemr/DynamicFormDTO.java | 6 + .../iemr/flw/dto/iemr/FormResponseDTO.java | 2 + .../flw/dto/iemr/LatestFormVersionDTO.java | 42 + .../iemr/flw/dto/iemr/QuestionOptionDTO.java | 3 + .../flw/dto/iemr/QuestionResponseDTO.java | 5 + .../provider/DiagnosticCancelResult.java | 14 + .../provider/DiagnosticProvider.java | 10 + .../provider/emrlite/EmrLiteProvider.java | 39 +- .../emrlite/EmrLiteRestTemplateConfig.java | 11 +- .../emrlite/dto/EmrLiteCancelRequest.java | 13 + .../iemr/flw/mapper/DynamicFormMapper.java | 1 + .../flw/masterEnum/DiagnosticOrderStatus.java | 7 +- .../iemr/flw/masterEnum/ValidationType.java | 5 +- .../flw/repo/identity/BeneficiaryRepo.java | 19 +- .../flw/repo/iemr/DiagnosticOrderRepo.java | 44 +- .../iemr/DynamicFormMigrationLogRepo.java | 34 + .../iemr/flw/repo/iemr/FormResponseRepo.java | 2 + .../iemr/flw/repo/iemr/FormSectionRepo.java | 16 + .../iemr/flw/repo/iemr/FormVersionRepo.java | 8 + .../flw/repo/iemr/OptionConditionRepo.java | 12 +- .../flw/repo/iemr/QuestionOptionRepo.java | 23 +- .../flw/repo/iemr/QuestionValidationRepo.java | 10 +- .../flw/repo/iemr/SectionQuestionRepo.java | 20 +- .../flw/repo/iemr/StopTBDiagnosticsRepo.java | 4 + .../iemr/StopTBGeneralExaminationRepo.java | 4 + .../flw/repo/iemr/StopTBGeneralOpdRepo.java | 4 + .../iemr/flw/repo/iemr/TBScreeningRepo.java | 4 + .../iemr/flw/repo/iemr/TBSuspectedRepo.java | 7 +- .../flw/repo/iemr/UserServiceRoleRepo.java | 47 +- .../DynamicFormMigrationApplier.java | 49 ++ .../migration/DynamicFormMigrationRunner.java | 73 ++ .../migration/FormStructureMigration.java | 78 ++ .../V001_1_CreateContactTracingVersion2.java | 108 +++ .../migration/V001_ReplaceTfuAdrOptions.java | 104 +++ .../V002_RenameNoOfContactsQuestion.java | 83 ++ ..._ChangeExposureSettingToDropdownMulti.java | 76 ++ .../V004_ChangeOccupationToDropdown.java | 76 ++ .../V005_AddAreaOfSharedSpaceQuestion.java | 115 +++ .../V006_PerRelationshipTypeOfSpace.java | 172 +++++ .../V007_AddRelationshipHoursQuestions.java | 129 ++++ ...008_ChangeRelationshipToDropdownMulti.java | 77 ++ .../migration/V009_BackfillOptionUuid.java | 62 ++ .../iemr/flw/service/BeneficiaryService.java | 3 + .../iemr/flw/service/CampConfigService.java | 62 +- .../flw/service/DiagnosticOrderService.java | 36 +- .../service/DynamicFormDefinitionService.java | 5 +- .../DynamicFormReconciliationService.java | 101 +++ .../service/DynamicFormResponseService.java | 6 + .../service/StopTBPrescriptionService.java | 721 ++++++++++++++++++ .../com/iemr/flw/service/StopTBService.java | 12 + .../iemr/flw/service/StopTBSyncService.java | 19 + .../flw/service/TBConfirmedCaseService.java | 11 +- .../iemr/flw/service/TBSuspectedService.java | 3 + .../service/impl/BeneficiaryServiceImpl.java | 234 ++++-- .../impl/DiagnosticDocumentServiceImpl.java | 2 +- .../impl/DiagnosticOrderServiceImpl.java | 684 +++++++++++++++-- .../impl/DiagnosticPollSchedulerService.java | 127 +-- .../DynamicFormDefinitionServiceImpl.java | 24 +- .../DynamicFormReconciliationServiceImpl.java | 329 ++++++++ .../impl/DynamicFormResponseServiceImpl.java | 69 +- .../service/impl/FormResponseItemSaver.java | 16 +- .../flw/service/impl/StopTBServiceImpl.java | 156 +++- .../service/impl/StopTBSyncServiceImpl.java | 483 ++++++++++++ .../impl/TBConfirmedCaseServiceImpl.java | 541 +------------ .../service/impl/TBStopVisitServiceImpl.java | 12 +- .../service/impl/TBSuspectedServiceImpl.java | 120 ++- .../flw/service/impl/UserServiceImpl.java | 172 ++++- .../service/impl/WorklistPagePrefetch.java | 191 +++++ .../iemr/flw/service/sync/StopTBSyncType.java | 151 ++++ .../com/iemr/flw/service/sync/SyncToken.java | 117 +++ .../iemr/flw/service/sync/UserSyncScope.java | 66 ++ .../com/iemr/flw/utils/ApiTimingFilter.java | 40 + .../flw/utils/response/OutputResponse.java | 9 + src/main/resources/application.properties | 2 +- .../service/sync/StopTBSyncCoverageTest.java | 106 +++ .../flw/service/sync/StopTBSyncTypeTest.java | 21 + .../iemr/flw/service/sync/SyncTokenTest.java | 51 ++ .../flw/service/sync/UserSyncScopeTest.java | 42 + 104 files changed, 5863 insertions(+), 859 deletions(-) create mode 100644 src/main/java/com/iemr/flw/controller/StopTBSyncController.java create mode 100644 src/main/java/com/iemr/flw/domain/iemr/DynamicFormMigrationLog.java create mode 100644 src/main/java/com/iemr/flw/dto/iemr/LatestFormVersionDTO.java create mode 100644 src/main/java/com/iemr/flw/integration/provider/DiagnosticCancelResult.java create mode 100644 src/main/java/com/iemr/flw/integration/provider/emrlite/dto/EmrLiteCancelRequest.java create mode 100644 src/main/java/com/iemr/flw/repo/iemr/DynamicFormMigrationLogRepo.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/DynamicFormMigrationApplier.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/DynamicFormMigrationRunner.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/FormStructureMigration.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V001_1_CreateContactTracingVersion2.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V001_ReplaceTfuAdrOptions.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V002_RenameNoOfContactsQuestion.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V003_ChangeExposureSettingToDropdownMulti.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V004_ChangeOccupationToDropdown.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V005_AddAreaOfSharedSpaceQuestion.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V006_PerRelationshipTypeOfSpace.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V007_AddRelationshipHoursQuestions.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V008_ChangeRelationshipToDropdownMulti.java create mode 100644 src/main/java/com/iemr/flw/seeder/migration/V009_BackfillOptionUuid.java create mode 100644 src/main/java/com/iemr/flw/service/DynamicFormReconciliationService.java create mode 100644 src/main/java/com/iemr/flw/service/StopTBPrescriptionService.java create mode 100644 src/main/java/com/iemr/flw/service/StopTBSyncService.java create mode 100644 src/main/java/com/iemr/flw/service/impl/DynamicFormReconciliationServiceImpl.java create mode 100644 src/main/java/com/iemr/flw/service/impl/StopTBSyncServiceImpl.java create mode 100644 src/main/java/com/iemr/flw/service/impl/WorklistPagePrefetch.java create mode 100644 src/main/java/com/iemr/flw/service/sync/StopTBSyncType.java create mode 100644 src/main/java/com/iemr/flw/service/sync/SyncToken.java create mode 100644 src/main/java/com/iemr/flw/service/sync/UserSyncScope.java create mode 100644 src/main/java/com/iemr/flw/utils/ApiTimingFilter.java create mode 100644 src/test/java/com/iemr/flw/service/sync/StopTBSyncCoverageTest.java create mode 100644 src/test/java/com/iemr/flw/service/sync/StopTBSyncTypeTest.java create mode 100644 src/test/java/com/iemr/flw/service/sync/SyncTokenTest.java create mode 100644 src/test/java/com/iemr/flw/service/sync/UserSyncScopeTest.java diff --git a/pom.xml b/pom.xml index 36f151d1f..63e8f2ff9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iemr.common.flw flw-api - 3.11.0 + 3.12.0 war FLW-API diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 862e4c314..b778ecfff 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -64,6 +64,7 @@ diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/i diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/ diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/ diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.xray.cancel-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/cancel/ diagnostic.emrlite.xray.username=@env.DIAGNOSTIC_EMRLITE_XRAY_USERNAME@ diagnostic.emrlite.xray.password=@env.DIAGNOSTIC_EMRLITE_XRAY_PASSWORD@ @@ -74,6 +75,7 @@ diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/ap diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/ diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/ diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.truenat.cancel-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/cancel/ diagnostic.emrlite.truenat.username=@env.DIAGNOSTIC_EMRLITE_TRUENAT_USERNAME@ diagnostic.emrlite.truenat.password=@env.DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD@ diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index 6c1f908c6..e38175a51 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -70,6 +70,7 @@ diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/i diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/ diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/ diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.xray.cancel-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/cancel/ diagnostic.emrlite.xray.username=${DIAGNOSTIC_EMRLITE_XRAY_USERNAME} diagnostic.emrlite.xray.password=${DIAGNOSTIC_EMRLITE_XRAY_PASSWORD} @@ -80,6 +81,7 @@ diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/ap diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/ diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/ diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/ +diagnostic.emrlite.truenat.cancel-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/cancel/ diagnostic.emrlite.truenat.username=${DIAGNOSTIC_EMRLITE_TRUENAT_USERNAME} diagnostic.emrlite.truenat.password=${DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD} diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index d85fa61a5..a1d4ebe55 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -2,7 +2,6 @@ server.port=8081 # FHIR Config fhir-url=http://localhost:8093/ - # TM Config tm-url=http://localhost:8089/ ##--------------------------------------------## Primary db------------------------------------------------------------------- @@ -24,11 +23,17 @@ springdoc.swagger-ui.enabled=true logging.path=logs/ logging.file.name=logs/flw-api.log -jwt.secret=my-32-character-ultra-secure-and-ultra-long-secret +jwt.secret=eefa40497bb9b2a8491b85069aff62e7596521c6816e471c464181b52eac7670ff91394a # Redis Config spring.redis.host=localhost +# Stop TB: when true, saves fail with an error if camp (vanID) is not configured +# instead of silently storing vanID=NULL (which then never gets synced to central) +stoptb.enforce.vanid=false +# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup +stoptb.van.id=0 + cors.allowed-origins=http://localhost:* source-address= @@ -44,56 +49,46 @@ abha.client.secret= abha.token.url= abha.xcmid= - - - - -# Diagnostic providers - -# Provider names: use the values supported by your application -diagnostic.provider.xray= -diagnostic.provider.truenat= - -# EMR Lite - Xray (base URL without trailing slash) -diagnostic.emrlite.xray.base-url=https:// +# GovThealth API Config +govthealth.user.details.url=${GOVTHEALTH_USER_DETAILS_URL} +govthealth.user.id=${GOVTHEALTH_USER_ID} +govthealth.password=${GOVTHEALTH_PASSWORD} + +# ── Diagnostic Device Integration ──────────────────────────────────────────── +# diagnostic.provider.xray / diagnostic.provider.truenat select the vendor per orderType family +# (XRAY_CHEST vs MTB/MTB_PLUS/MDR_RIF), each must be one of com.iemr.flw.masterEnum.DiagnosticProviderCode +diagnostic.provider.xray=${DIAGNOSTIC_PROVIDER_XRAY} +diagnostic.provider.truenat=${DIAGNOSTIC_PROVIDER_TRUENAT} + +# EMR Lite - xray group (same base-url as truenat for now; split so a distinct vendor/tenant can be +# swapped in for either group later without a code change) +diagnostic.emrlite.xray.base-url=${DIAGNOSTIC_EMRLITE_XRAY_BASE_URL} diagnostic.emrlite.xray.login-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/login/ diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/getAccessToken/ diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/ diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/ diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/ -diagnostic.emrlite.xray.username= -diagnostic.emrlite.xray.password= +diagnostic.emrlite.xray.cancel-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/cancel/ +diagnostic.emrlite.xray.username=${DIAGNOSTIC_EMRLITE_XRAY_USERNAME} +diagnostic.emrlite.xray.password=${DIAGNOSTIC_EMRLITE_XRAY_PASSWORD} -# EMR Lite - Truenat -diagnostic.emrlite.truenat.base-url=https:// +# EMR Lite - truenat group (MTB/MTB_PLUS/MDR_RIF); same value as xray for now +diagnostic.emrlite.truenat.base-url=${DIAGNOSTIC_EMRLITE_TRUENAT_BASE_URL} diagnostic.emrlite.truenat.login-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/login/ diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/getAccessToken/ diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/ diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/ diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/ -diagnostic.emrlite.truenat.username= -diagnostic.emrlite.truenat.password= - -# Token TTL: replace with vendor-configured durations in seconds -diagnostic.emrlite.refresh-ttl-seconds=86400 +diagnostic.emrlite.truenat.cancel-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/cancel/ +diagnostic.emrlite.truenat.username=${DIAGNOSTIC_EMRLITE_TRUENAT_USERNAME} +diagnostic.emrlite.truenat.password=${DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD} -# Example: polling every 60 seconds -diagnostic.poll.xray.tick-ms=60000 -diagnostic.poll.truenat.tick-ms=60000 +diagnostic.emrlite.token-ttl-seconds=${DIAGNOSTIC_EMRLITE_TOKEN_TTL_SECONDS} +diagnostic.emrlite.refresh-ttl-seconds=${DIAGNOSTIC_EMRLITE_REFRESH_TTL_SECONDS} -# Example: daily expiry at 11:59 PM in scheduler timezone -diagnostic.poll.expiry-cron=0 59 23 * * * +diagnostic.poll.xray.tick-ms=${DIAGNOSTIC_POLL_XRAY_TICK_MS} +diagnostic.poll.truenat.tick-ms=${DIAGNOSTIC_POLL_TRUENAT_TICK_MS} +# Daily cutoff (cron expression) after which all outstanding PENDING/IN_PROGRESS orders are marked EXPIRED +diagnostic.poll.expiry-cron=${DIAGNOSTIC_POLL_EXPIRY_CRON} -# Local folder (Windows: use forward slashes) -diagnostic.documents.storage-root=C:/amrit/diagnostic-documents -stoptb.enforce.vanid=false -# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup -stoptb.van.id=0 - - - -# GovThealth API Config -govthealth.user.details.url=@env.GOVTHEALTH_USER_DETAILS_URL@ -govthealth.user.id=@env.GOVTHEALTH_USER_ID@ -govthealth.password=@env.GOVTHEALTH_PASSWORD@ -common-api-base-url= +diagnostic.documents.storage-root=${DIAGNOSTIC_DOCUMENTS_STORAGE_ROOT} diff --git a/src/main/java/com/iemr/flw/controller/DiagnosticOrderController.java b/src/main/java/com/iemr/flw/controller/DiagnosticOrderController.java index 8eb9476b7..1725b5afc 100644 --- a/src/main/java/com/iemr/flw/controller/DiagnosticOrderController.java +++ b/src/main/java/com/iemr/flw/controller/DiagnosticOrderController.java @@ -37,10 +37,11 @@ public DiagnosticOrderController(DiagnosticOrderService diagnosticOrderService) @PostMapping("/order/push") @Operation(summary = "Push a diagnostic order to the configured provider") - public String pushOrder(@RequestBody @Valid DiagnosticOrderRequestDto request) { + public String pushOrder(@RequestBody @Valid DiagnosticOrderRequestDto request, + @RequestHeader("JwtToken") String jwtToken) { OutputResponse response = new OutputResponse(); try { - DiagnosticOrder order = diagnosticOrderService.createAndPushOrder(request); + DiagnosticOrder order = diagnosticOrderService.createAndPushOrderByUser(request, jwtToken); response.setResponse(new Gson().toJson(order)); } catch (Exception e) { logger.error("Error in pushOrder: {}", e.getMessage()); @@ -128,14 +129,17 @@ public String pollOrder(@RequestParam Long beneficiaryId, @RequestParam String o } @PostMapping("/order/manualResult") - @Operation(summary = "Manually submit a diagnostic result for a beneficiary's latest order of the given " - + "type, for use when no vendor device is integrated. Stored as-is; tbPresence, tbConfidence, and " - + "drugResistancePresence are left null since nothing derives them. Rejected if that order is " - + "already COMPLETED.") - public String submitManualResult(@RequestBody @Valid ManualDiagnosticResultRequestDto request) { + @Operation(summary = "Exactly one of resultSummary/reasonToClose is required. resultSummary: manually submit " + + "a diagnostic result for a beneficiary's latest order of the given type, for use when no vendor " + + "device is integrated. Stored as-is; tbPresence, tbConfidence, and drugResistancePresence are left " + + "null since nothing derives them. Rejected if that order is already COMPLETED. reasonToClose: close " + + "the order instead (same behavior as reasonToClose on /order/push), sourcing patient/orderEvent " + + "from the beneficiary's existing order for this type.") + public String submitManualResult(@RequestBody @Valid ManualDiagnosticResultRequestDto request, + @RequestHeader("JwtToken") String jwtToken) { OutputResponse response = new OutputResponse(); try { - DiagnosticOrderResultDto result = diagnosticOrderService.submitManualResult(request); + DiagnosticOrderResultDto result = diagnosticOrderService.submitManualResult(request, jwtToken); response.setResponse(new GsonBuilder().serializeNulls().create().toJson(result)); } catch (Exception e) { logger.error("Error in submitManualResult: {}", e.getMessage()); diff --git a/src/main/java/com/iemr/flw/controller/DynamicFormController.java b/src/main/java/com/iemr/flw/controller/DynamicFormController.java index 59295cbf7..254313e93 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/controller/StopTBController.java b/src/main/java/com/iemr/flw/controller/StopTBController.java index 7f73d29e2..e9a38513c 100644 --- a/src/main/java/com/iemr/flw/controller/StopTBController.java +++ b/src/main/java/com/iemr/flw/controller/StopTBController.java @@ -2,6 +2,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.iemr.flw.service.StopTBPrescriptionService; import com.iemr.flw.service.StopTBService; import com.iemr.flw.utils.response.OutputResponse; import io.swagger.v3.oas.annotations.Operation; @@ -51,7 +52,7 @@ public String getAllGeneralExaminations(@RequestBody Map body) { if (raw == null) throw new Exception("providerServiceMapID is required"); Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null; Map data = stopTBService.getAllGeneralExaminations(Integer.parseInt(raw.toString()), villageID); - response.setResponse(gson.toJson(data)); + response.setResponse(gson.toJsonTree(data)); } catch (Exception e) { logger.error("Error in getAllGeneralExaminations: " + e); response.setError(5000, "Error fetching general examinations: " + e.getMessage()); @@ -84,7 +85,7 @@ public String getAllNurseTBScreenings(@RequestBody Map body) { if (raw == null) throw new Exception("providerServiceMapID is required"); Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null; Map data = stopTBService.getAllNurseTBScreenings(Integer.parseInt(raw.toString()), villageID); - response.setResponse(gson.toJson(data)); + response.setResponse(gson.toJsonTree(data)); } catch (Exception e) { logger.error("Error in getAllNurseTBScreenings: " + e); response.setError(5000, "Error fetching TB screenings: " + e.getMessage()); @@ -101,6 +102,10 @@ public String saveGeneralOpd(@RequestBody List> dataList) { try { List> result = stopTBService.saveGeneralOpd(dataList); response.setResponse(gson.toJson(result)); + } catch (StopTBPrescriptionService.InsufficientStockException e) { + // Nothing was saved; the app shows this and lets the nurse lower the quantity. + logger.warn("saveGeneralOpd rejected: " + e.getMessage()); + response.setError(5000, e.getMessage()); } catch (Exception e) { logger.error("Error in saveGeneralOpd: " + e); response.setError(5000, "Error saving general OPD: " + e.getMessage()); @@ -117,7 +122,7 @@ public String getAllGeneralOpd(@RequestBody Map body) { if (raw == null) throw new Exception("providerServiceMapID is required"); Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null; Map data = stopTBService.getAllGeneralOpd(Integer.parseInt(raw.toString()), villageID); - response.setResponse(gson.toJson(data)); + response.setResponse(gson.toJsonTree(data)); } catch (Exception e) { logger.error("Error in getAllGeneralOpd: " + e); response.setError(5000, "Error fetching general OPD records: " + e.getMessage()); @@ -150,7 +155,7 @@ public String getAllDiagnostics(@RequestBody Map body) { if (raw == null) throw new Exception("providerServiceMapID is required"); Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null; Map data = stopTBService.getAllDiagnostics(Integer.parseInt(raw.toString()), villageID); - response.setResponse(gson.toJson(data)); + response.setResponse(gson.toJsonTree(data)); } catch (Exception e) { logger.error("Error in getAllDiagnostics: " + e); response.setError(5000, "Error fetching diagnostics records: " + e.getMessage()); diff --git a/src/main/java/com/iemr/flw/controller/StopTBSyncController.java b/src/main/java/com/iemr/flw/controller/StopTBSyncController.java new file mode 100644 index 000000000..23201436f --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/StopTBSyncController.java @@ -0,0 +1,77 @@ +package com.iemr.flw.controller; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.iemr.flw.service.StopTBSyncService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.response.OutputResponse; +import io.swagger.v3.oas.annotations.Operation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/stoptb/sync") +public class StopTBSyncController { + + private final Logger logger = LoggerFactory.getLogger(StopTBSyncController.class); + + private final Gson gson = new GsonBuilder().serializeNulls().create(); + + @Autowired + private StopTBSyncService stopTBSyncService; + + @Autowired + private JwtUtil jwtUtil; + + /** + * Headers: JwtToken (required; the user's role mappings decide the allowed service and villages). + * Body: { token: string|null, providerServiceMapID: int, villageIds: [int] (empty = all of the user's + * villages), types: [string], limit: int }. + * types: the record types the app applies (all when omitted); changing it requires a new snapshot. + * Response: { supported, serverId, snapshot, items: [{type, op, key, version, data}], nextToken, hasMore }. + * Call again with nextToken while hasMore is true. On a server without the change log (AMRIT-DB before V132) the + * response is { supported: false } and the app keeps using the getAll endpoints. + */ + @PostMapping("/changes") + @Operation(summary = "STOP-TB records changed since the token (first call: everything in the villages)") + public String getChanges(@RequestBody Map body, + @RequestHeader(value = "Authorization", required = false) String authorization, + @RequestHeader(value = "JwtToken", required = false) String jwtToken) { + OutputResponse response = new OutputResponse(); + try { + // The user decides which villages may be synced, so the JWT is required here even + // where the request filter would let a mobile request through without one. + if (jwtToken == null || jwtToken.isBlank()) throw new IllegalArgumentException("JwtToken header is required"); + Integer userId = jwtUtil.extractUserId(jwtToken); + Object token = body.get("token"); + Integer psm = body.get("providerServiceMapID") != null + ? Integer.parseInt(body.get("providerServiceMapID").toString()) : null; + List villageIds = new ArrayList<>(); + if (body.get("villageIds") instanceof List) { + for (Object v : (List) body.get("villageIds")) { + if (v != null) villageIds.add((int) Double.parseDouble(v.toString())); + } + } + List types = new ArrayList<>(); + if (body.get("types") instanceof List) { + for (Object t : (List) body.get("types")) { + if (t != null) types.add(t.toString()); + } + } + Integer limit = body.get("limit") != null ? (int) Double.parseDouble(body.get("limit").toString()) : null; + Map data = stopTBSyncService.getChanges( + userId, token != null ? token.toString() : null, psm, villageIds, types, limit, authorization); + response.setResponse(gson.toJson(data)); + } catch (Exception e) { + logger.error("Error in sync/changes: " + e); + response.setError(5000, "Error fetching changes: " + e.getMessage()); + } + return response.toString(); + } +} 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 d96ee5abc..8354670ee 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java @@ -102,11 +102,13 @@ public class RMNCHBeneficiaryDetailsRmnch { @Column(name = "longitude") private BigDecimal longitude; - @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") diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticDocument.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticDocument.java index 508617747..8d8ecff25 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticDocument.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticDocument.java @@ -84,7 +84,7 @@ public class DiagnosticDocument { @Column(name = "parkingPlaceID") private Integer parkingPlaceID; - @Column(name = "vanSerialNo") + @Column(name = "vanSerialNo", updatable = false) private Long vanSerialNo; @Column(name = "synced_by") diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java index ae7dc52db..5ea9a4589 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticOrder.java @@ -8,8 +8,7 @@ import java.sql.Timestamp; @Entity -@Table(name = "tb_diagnostic_order", schema = "db_iemr", - uniqueConstraints = @UniqueConstraint(columnNames = {"beneficiary_id", "visitCode", "order_type"})) +@Table(name = "tb_diagnostic_order", schema = "db_iemr") @Data public class DiagnosticOrder { @@ -59,6 +58,9 @@ public class DiagnosticOrder { @Column(name = "push_response_json", columnDefinition = "LONGTEXT") private String pushResponseJson; + @Column(name = "cancel_response_json", columnDefinition = "LONGTEXT") + private String cancelResponseJson; + @Column(name = "patient_first_name", length = 100) private String patientFirstName; @@ -82,6 +84,9 @@ public class DiagnosticOrder { @Column(name = "modified_by") private String modifiedBy; + @Column(name = "manually_entered_by") + private String manuallyEnteredBy; + @UpdateTimestamp @Column(name = "last_mod_date") private Timestamp lastModDate; @@ -101,7 +106,7 @@ public class DiagnosticOrder { @Column(name = "processed") private String processed = "N"; - @Column(name = "vanSerialNo") + @Column(name = "vanSerialNo", updatable = false) private Long vanSerialNo; @Column(name = "synced_by") diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticProviderToken.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticProviderToken.java index 6ee5ea126..198667f38 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticProviderToken.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticProviderToken.java @@ -46,7 +46,7 @@ public class DiagnosticProviderToken { @Column(name = "parkingPlaceID") private Integer parkingPlaceID; - @Column(name = "vanSerialNo") + @Column(name = "vanSerialNo", updatable = false) private Long vanSerialNo; @Column(name = "synced_by") diff --git a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticResult.java b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticResult.java index 734e98e98..55e5a0ca0 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DiagnosticResult.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DiagnosticResult.java @@ -70,7 +70,7 @@ public class DiagnosticResult { @Column(name = "parkingPlaceID") private Integer parkingPlaceID; - @Column(name = "vanSerialNo") + @Column(name = "vanSerialNo", updatable = false) private Long vanSerialNo; @Column(name = "synced_by") diff --git a/src/main/java/com/iemr/flw/domain/iemr/DynamicFormMigrationLog.java b/src/main/java/com/iemr/flw/domain/iemr/DynamicFormMigrationLog.java new file mode 100644 index 000000000..1ff0158d7 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/DynamicFormMigrationLog.java @@ -0,0 +1,53 @@ +/* + * 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.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.CreationTimestamp; + +import java.sql.Timestamp; + +/** + * One row per applied {@code com.iemr.flw.seeder.migration.FormStructureMigration}, keyed by its + * stable migrationId — lets {@code DynamicFormMigrationRunner} skip a migration it has already run. + */ +@Entity +@Table(name = "t_dynamic_form_migration_log", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DynamicFormMigrationLog { + + @Id + @Column(name = "migrationId", length = 50) + private String migrationId; + + @CreationTimestamp + @Column(name = "appliedAt", nullable = false, updatable = false) + private Timestamp appliedAt; +} 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 b06ce48e7..0f5e687ee 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java @@ -90,6 +90,11 @@ public class FormSection { @Column(name = "isEditable", nullable = false) private Boolean isEditable = false; + /** Soft-delete flag: false means removed from its version. Never hard-deleted — historical + * section responses reference it. */ + @Column(name = "isActive", nullable = false) + private Boolean isActive = true; + @Column(name = "created_by", length = 100) private String createdBy; 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 397fc22f6..1f26da77d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java @@ -71,6 +71,11 @@ public class FormVersion { @Column(name = "isLatest", nullable = false) private Boolean isLatest = true; + /** Soft-delete flag: false means the version is retired. Never hard-deleted — historical + * form responses reference their version. */ + @Column(name = "isActive", nullable = false) + private Boolean isActive = true; + @Column(name = "createdAt", nullable = false, updatable = false) private Timestamp createdAt; 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 975a23ad2..3a8908466 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java +++ b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java @@ -74,6 +74,10 @@ public class OptionCondition { @ToString.Exclude private FormSection targetSection; + /** Soft-delete flag: false means removed from its option. Never hard-deleted. */ + @Column(name = "isActive", nullable = false) + private Boolean isActive = true; + @Column(name = "created_by", length = 100) private String createdBy; 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 c732045a0..cbbbdc83d 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,12 +71,21 @@ 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; @Column(name = "displayOrder", nullable = false) private Integer displayOrder; + /** Soft-delete flag: false means removed from its question. Never hard-deleted — historical + * QuestionResponse rows reference optionId as a plain Long outside JPA's cascade graph. */ + @Column(name = "isActive", nullable = false) + private Boolean isActive = true; + @Column(name = "created_by", length = 100) private String createdBy; @@ -107,4 +117,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/domain/iemr/QuestionValidation.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java index 300853c53..ee2c3a34d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java @@ -72,6 +72,10 @@ public class QuestionValidation { @Column(name = "errorMessage", nullable = false, length = 500) private String errorMessage; + /** Soft-delete flag: false means removed from its question. Never hard-deleted. */ + @Column(name = "isActive", nullable = false) + private Boolean isActive = true; + @Column(name = "created_by", length = 100) private String createdBy; 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 67fc109f6..5660405ce 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java @@ -98,6 +98,11 @@ public class SectionQuestion { @Column(name = "containsPii", nullable = false) private Boolean containsPii = false; + /** Soft-delete flag: false means unlinked from its section. Never hard-deleted — historical + * QuestionResponse rows reference questionId as a plain Long outside JPA's cascade graph. */ + @Column(name = "isActive", nullable = false) + private Boolean isActive = true; + @Column(name = "created_by", length = 100) private String createdBy; diff --git a/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java b/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java index 400074a06..14e4aba6a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java +++ b/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java @@ -135,7 +135,7 @@ public class StopTBDiagnostics { @Column(name = "processed") private String processed = "N"; - @Column(name = "vanSerialNo") + @Column(name = "vanSerialNo", updatable = false) private Long vanSerialNo; @Column(name = "synced_by") diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java index 01170cf91..4af3c078b 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java @@ -195,28 +195,21 @@ public class TBScreening { @Column(name = "createdDate") private java.sql.Timestamp createdDate; - @Column(name = "risk_factor", columnDefinition = "TEXT") - private String riskFactor; - - @Column(name = "fatigue") - private Boolean fatigue; - @Column(name = "chest_pain") private Boolean chestPain; - @Column(name = "short_breath") - private Boolean shortBreath; + @Column(name = "shortness_of_breath") + private Boolean shortnessOfBreath; - @Column(name = "synced_by") - private String syncedBy; - - @org.hibernate.annotations.CreationTimestamp - @Column(name = "synced_date") - private Timestamp syncedDate; + @Column(name = "fatigue") + private Boolean fatigue; - @Column(name = "failure_to_gainWeight") + @Column(name = "failure_to_gain_weight") private Boolean failureToGainWeight; - @Column(name = "decreased_activity_playfulness ") - private Boolean decreasedActivityOrPlayfulness ; + @Column(name = "decreased_activity_or_playfulness") + private Boolean decreasedActivityOrPlayfulness; + + @Column(name = "others") + private Boolean others; } diff --git a/src/main/java/com/iemr/flw/dto/DiagnosticOrderRequestDto.java b/src/main/java/com/iemr/flw/dto/DiagnosticOrderRequestDto.java index 6ed0e03fe..abf8475ea 100644 --- a/src/main/java/com/iemr/flw/dto/DiagnosticOrderRequestDto.java +++ b/src/main/java/com/iemr/flw/dto/DiagnosticOrderRequestDto.java @@ -14,15 +14,12 @@ public class DiagnosticOrderRequestDto { @NotNull private Long beneficiaryId; - @NotNull - private Long visitCode; - @NotNull private String orderType; private String orderEvent; - private String reasonForRefusal; + private String reasonToClose; @NotNull @Valid diff --git a/src/main/java/com/iemr/flw/dto/DiagnosticOrderResultDto.java b/src/main/java/com/iemr/flw/dto/DiagnosticOrderResultDto.java index 92eaa03d5..531800f7d 100644 --- a/src/main/java/com/iemr/flw/dto/DiagnosticOrderResultDto.java +++ b/src/main/java/com/iemr/flw/dto/DiagnosticOrderResultDto.java @@ -13,7 +13,7 @@ public class DiagnosticOrderResultDto { private String providerStatus; private String resultSummary; private String errorMessage; - private String reasonForRefusal; + private String reasonToClose; private Boolean tbPresence; private Double tbConfidence; private Boolean drugResistancePresence; diff --git a/src/main/java/com/iemr/flw/dto/DiagnosticOrderStatusSummaryDto.java b/src/main/java/com/iemr/flw/dto/DiagnosticOrderStatusSummaryDto.java index 4e18e0bb1..88eafcab7 100644 --- a/src/main/java/com/iemr/flw/dto/DiagnosticOrderStatusSummaryDto.java +++ b/src/main/java/com/iemr/flw/dto/DiagnosticOrderStatusSummaryDto.java @@ -12,8 +12,7 @@ public class DiagnosticOrderStatusSummaryDto { private List awaitingProviderResult; private List completed; - private List pollingTimedOut; private List failed; - private List refused; + private List closed; private List awaitingManualEntry; } diff --git a/src/main/java/com/iemr/flw/dto/ManualDiagnosticResultRequestDto.java b/src/main/java/com/iemr/flw/dto/ManualDiagnosticResultRequestDto.java index 12bd70cdb..cd6a10a83 100644 --- a/src/main/java/com/iemr/flw/dto/ManualDiagnosticResultRequestDto.java +++ b/src/main/java/com/iemr/flw/dto/ManualDiagnosticResultRequestDto.java @@ -1,6 +1,5 @@ package com.iemr.flw.dto; -import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import lombok.NoArgsConstructor; @@ -15,6 +14,7 @@ public class ManualDiagnosticResultRequestDto { @NotNull private String orderType; - @NotBlank private String resultSummary; + + private String reasonToClose; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java index 9d755546a..38fe27058 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java @@ -21,6 +21,7 @@ */ package com.iemr.flw.dto.iemr; +import com.fasterxml.jackson.annotation.JsonInclude; import com.iemr.flw.masterEnum.FormType; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; @@ -65,4 +66,9 @@ public class DynamicFormDTO { @Valid private List sections = new ArrayList<>(); + + /** Every version's full definition, oldest first — populated only by getAllForms (the top-level + * fields above stay the latest version); omitted from the JSON elsewhere and ignored on write. */ + @JsonInclude(JsonInclude.Include.NON_NULL) + private List versions; } 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 efc74085b..3fa5d7a1d 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java @@ -47,6 +47,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 000000000..ee1d197e5 --- /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 3c2b14409..c1d969de6 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java @@ -54,6 +54,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 1bcff9c96..f4002ddfa 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java @@ -43,8 +43,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/integration/provider/DiagnosticCancelResult.java b/src/main/java/com/iemr/flw/integration/provider/DiagnosticCancelResult.java new file mode 100644 index 000000000..f025bacba --- /dev/null +++ b/src/main/java/com/iemr/flw/integration/provider/DiagnosticCancelResult.java @@ -0,0 +1,14 @@ +package com.iemr.flw.integration.provider; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DiagnosticCancelResult { + private boolean success; + private String rawResponseJson; + private String errorMessage; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/integration/provider/DiagnosticProvider.java b/src/main/java/com/iemr/flw/integration/provider/DiagnosticProvider.java index 9737cba02..47cd3ee30 100644 --- a/src/main/java/com/iemr/flw/integration/provider/DiagnosticProvider.java +++ b/src/main/java/com/iemr/flw/integration/provider/DiagnosticProvider.java @@ -11,6 +11,16 @@ public interface DiagnosticProvider { DiagnosticPollResult pollResult(DiagnosticOrder order, boolean includeAssets) throws Exception; + /** + * Notifies the vendor that this order is being closed out without (or regardless of) a result, + * so it stops tracking/processing it on their end. Only call for an order actually known to the + * vendor (i.e. previously pushed) — calling this for an order that was never pushed is meaningless. + * The raw response is returned (on both success and a provider-level rejection) so the caller can + * persist it; only a transport-level failure (unreachable, timeout) throws instead, since there's + * no response body to return in that case. + */ + DiagnosticCancelResult cancelOrder(DiagnosticOrder order, String reason) throws Exception; + /** * Lightweight liveness check against the vendor group serving this orderType. Never throws — * returns false on any failure (unreachable, non-2xx, unparsable response, unconfigured URL). diff --git a/src/main/java/com/iemr/flw/integration/provider/emrlite/EmrLiteProvider.java b/src/main/java/com/iemr/flw/integration/provider/emrlite/EmrLiteProvider.java index 0aa20d631..754711ce1 100644 --- a/src/main/java/com/iemr/flw/integration/provider/emrlite/EmrLiteProvider.java +++ b/src/main/java/com/iemr/flw/integration/provider/emrlite/EmrLiteProvider.java @@ -4,6 +4,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.iemr.flw.domain.iemr.DiagnosticOrder; +import com.iemr.flw.integration.provider.DiagnosticCancelResult; import com.iemr.flw.integration.provider.DiagnosticDocumentAsset; import com.iemr.flw.integration.provider.DiagnosticPollResult; import com.iemr.flw.integration.provider.DiagnosticProvider; @@ -60,6 +61,12 @@ public class EmrLiteProvider implements DiagnosticProvider { @Value("${diagnostic.emrlite.truenat.ping-url}") private String truenatPingUrl; + @Value("${diagnostic.emrlite.xray.cancel-url}") + private String xrayCancelUrl; + + @Value("${diagnostic.emrlite.truenat.cancel-url}") + private String truenatCancelUrl; + @Autowired @Qualifier("emrLiteRestTemplate") private RestTemplate restTemplate; @@ -158,6 +165,34 @@ public DiagnosticPollResult pollResult(DiagnosticOrder order, boolean includeAss tbPresence, tbConfidence, drugResistancePresence); } + @Override + public DiagnosticCancelResult cancelOrder(DiagnosticOrder order, String reason) throws Exception { + EmrLiteCancelRequest request = new EmrLiteCancelRequest(order.getExternalOrderId(), reason); + String cancelUrl = DiagnosticOrderType.XRAY_CHEST.name().equals(order.getOrderType()) + ? xrayCancelUrl : truenatCancelUrl; + String responseBody; + try { + responseBody = doPost(cancelUrl, gson.toJson(request)); + } catch (HttpStatusCodeException e) { + String body = e.getResponseBodyAsString(); + logger.warn("Provider HTTP error on order cancel: externalOrderId={}, status={}", + order.getExternalOrderId(), e.getStatusCode()); + return new DiagnosticCancelResult(false, body, "HTTP " + e.getStatusCode()); + } + + EmrLiteProviderResponse envelope = gson.fromJson(responseBody, EmrLiteProviderResponse.class); + if (envelope == null || !envelope.isSuccess()) { + logger.warn("Provider rejected order cancel: externalOrderId={}, message={}", + order.getExternalOrderId(), envelope != null ? envelope.getMessage() : null); + return new DiagnosticCancelResult(false, responseBody, + envelope != null ? envelope.getMessage() : "empty response"); + } + + logger.info("Order cancelled on provider: externalOrderId={}, reason={}", + order.getExternalOrderId(), reason); + return new DiagnosticCancelResult(true, responseBody, null); + } + @Override public boolean checkHealth(DiagnosticOrderType orderType) { String pingUrl = DiagnosticOrderType.XRAY_CHEST.equals(orderType) ? xrayPingUrl : truenatPingUrl; @@ -236,8 +271,8 @@ private DiagnosticOrderStatus deriveOrderStatus(EmrLiteResultResponse result) { DiagnosticOrderStatus topLevelStatus = DiagnosticOrderStatus.fromString(result.getStatus()); if (topLevelStatus == DiagnosticOrderStatus.COMPLETED || topLevelStatus == DiagnosticOrderStatus.FAILED) { // Components contradict a terminal top-level status — only the components map may - // resolve to a terminal state; treat this as still in progress. - return DiagnosticOrderStatus.IN_PROGRESS; + // resolve to a terminal state; treat this as still pending. + return DiagnosticOrderStatus.PENDING; } return topLevelStatus; } diff --git a/src/main/java/com/iemr/flw/integration/provider/emrlite/EmrLiteRestTemplateConfig.java b/src/main/java/com/iemr/flw/integration/provider/emrlite/EmrLiteRestTemplateConfig.java index 87079a183..16af36ecf 100644 --- a/src/main/java/com/iemr/flw/integration/provider/emrlite/EmrLiteRestTemplateConfig.java +++ b/src/main/java/com/iemr/flw/integration/provider/emrlite/EmrLiteRestTemplateConfig.java @@ -14,10 +14,17 @@ public class EmrLiteRestTemplateConfig { private static final int VENDOR_CALL_TIMEOUT_MS = 20000; + // Result responses carry document assets inline as base64, so reads get more headroom than connects. + private static final int VENDOR_READ_TIMEOUT_MS = 60000; + private static final int PING_TIMEOUT_MS = 5000; + // Timeouts are required, not optional: order pushes run while holding the per-beneficiary+orderType + // order lock (see DiagnosticOrderServiceImpl), so a hung vendor call without them would hold that lock forever. @Bean public RestTemplate emrLiteRestTemplate(EmrLiteTokenManager emrLiteTokenManager) { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(VENDOR_CALL_TIMEOUT_MS); + factory.setReadTimeout(VENDOR_READ_TIMEOUT_MS); RestTemplate restTemplate = new RestTemplate(factory); restTemplate.getInterceptors().add(new EmrLiteAuthInterceptor(emrLiteTokenManager)); return restTemplate; @@ -28,8 +35,8 @@ public RestTemplate emrLiteRestTemplate(EmrLiteTokenManager emrLiteTokenManager) @Bean public RestTemplate emrLitePingRestTemplate() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); - factory.setConnectTimeout(VENDOR_CALL_TIMEOUT_MS); - factory.setReadTimeout(VENDOR_CALL_TIMEOUT_MS); + factory.setConnectTimeout(PING_TIMEOUT_MS); + factory.setReadTimeout(PING_TIMEOUT_MS); return new RestTemplate(factory); } } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/integration/provider/emrlite/dto/EmrLiteCancelRequest.java b/src/main/java/com/iemr/flw/integration/provider/emrlite/dto/EmrLiteCancelRequest.java new file mode 100644 index 000000000..51f8320da --- /dev/null +++ b/src/main/java/com/iemr/flw/integration/provider/emrlite/dto/EmrLiteCancelRequest.java @@ -0,0 +1,13 @@ +package com.iemr.flw.integration.provider.emrlite.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EmrLiteCancelRequest { + private String externalOrderId; + private String reason; +} diff --git a/src/main/java/com/iemr/flw/mapper/DynamicFormMapper.java b/src/main/java/com/iemr/flw/mapper/DynamicFormMapper.java index 551e93a6d..9f7abac5b 100644 --- a/src/main/java/com/iemr/flw/mapper/DynamicFormMapper.java +++ b/src/main/java/com/iemr/flw/mapper/DynamicFormMapper.java @@ -48,6 +48,7 @@ public interface DynamicFormMapper { @Mapping(target = "sections", ignore = true) @Mapping(target = "versionNumber", ignore = true) + @Mapping(target = "versions", ignore = true) DynamicFormDTO toDto(DynamicForm entity); FormVersionDTO toDto(FormVersion entity); diff --git a/src/main/java/com/iemr/flw/masterEnum/DiagnosticOrderStatus.java b/src/main/java/com/iemr/flw/masterEnum/DiagnosticOrderStatus.java index 9a0a8ec23..ce444fcb0 100644 --- a/src/main/java/com/iemr/flw/masterEnum/DiagnosticOrderStatus.java +++ b/src/main/java/com/iemr/flw/masterEnum/DiagnosticOrderStatus.java @@ -5,13 +5,14 @@ public enum DiagnosticOrderStatus { IN_PROGRESS, COMPLETED, FAILED, - CANCELLED, - EXPIRED, - REFUSED, + CLOSED, MANUAL_ENTRY; public static DiagnosticOrderStatus fromString(String value) { if (value == null) return PENDING; + // IN_PROGRESS is kept only as a legacy/historical value (old rows, backward-compat reporting + // queries) — it is never freshly assigned. A vendor reporting "IN_PROGRESS" is just PENDING. + if (IN_PROGRESS.name().equalsIgnoreCase(value)) return PENDING; for (DiagnosticOrderStatus status : values()) { if (status.name().equalsIgnoreCase(value)) { return status; diff --git a/src/main/java/com/iemr/flw/masterEnum/ValidationType.java b/src/main/java/com/iemr/flw/masterEnum/ValidationType.java index 931e24699..ed7891588 100644 --- a/src/main/java/com/iemr/flw/masterEnum/ValidationType.java +++ b/src/main/java/com/iemr/flw/masterEnum/ValidationType.java @@ -38,5 +38,8 @@ public enum ValidationType { REGEX, /** Field becomes mandatory when another field equals a specific value. * validationParam format: "QUESTION_UUID=OPTION_VALUE" e.g. "Q-GENDER=FEMALE". */ - MANDATORY_IF + MANDATORY_IF, + /** Display unit for a numeric answer. validationParam = unit label e.g. "sq. m.". + * Informational only — not a rule the answer is checked against. */ + UNIT } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java index d37789d11..498bc3720 100644 --- a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java +++ b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java @@ -47,7 +47,11 @@ Page getBenDataWithinDates( @Query(value = " SELECT t FROM RMNCHMBeneficiaryaddress t WHERE t.createdBy = :userName ") Page getBenDataByUser(@Param("userName") String userName, Pageable pageable); - @Query(value = " SELECT t FROM RMNCHMBeneficiarymapping t WHERE t.benAddressId = :addressID") + // BenAddressId can have more than one mapping row (confirmed live: address-ID collisions + // between old/test registrations and real ones). Order by PK desc, same "latest wins" + // convention already used for findByBenRegIdFromMapping, so callers picking .get(0) get + // the newest mapping deterministically instead of whichever row the DB returns first. + @Query(value = " SELECT t FROM RMNCHMBeneficiarymapping t WHERE t.benAddressId = :addressID ORDER BY t.benMapId DESC") List getByAddressID(@Param("addressID") BigInteger addressID); @Query(value = " SELECT t FROM RMNCHMBeneficiarymapping t WHERE t.benRegId = :BenRegId") @@ -80,7 +84,11 @@ Page getBenDataWithinDates( @Query(value = " SELECT t.beneficiaryID FROM RMNCHMBeneficiaryregidmapping t WHERE t.benRegId = :benRegID ") BigInteger getBenIdFromRegID(@Param("benRegID") Long benRegID); - @Query(value = " SELECT t FROM RMNCHBeneficiaryDetailsRmnch t WHERE t.BenRegId =:benRegID ") + // BenRegId has no unique constraint on i_beneficiarydetails_rmnch — a beneficiary can have + // more than one row (confirmed live: duplicates, some created well after the original with + // a household link the older row never got). Order by PK desc so callers picking .get(0) + // get the latest row, not whichever one the DB happens to return first. + @Query(value = " SELECT t FROM RMNCHBeneficiaryDetailsRmnch t WHERE t.BenRegId =:benRegID ORDER BY t.beneficiaryDetails_RmnchId DESC ") List getDetailsByRegID(@Param("benRegID") Long benRegID); @Query(value = " SELECT t FROM RMNCHBornBirthDetails t WHERE t.BenRegId =:benRegID ") @@ -99,6 +107,13 @@ Page getBenDataWithinDates( @Query(nativeQuery = true, value = " SELECT HealthID,HealthIdNumber,isNewAbha FROM db_iemr.t_healthid WHERE HealthIdNumber = :healthIdNumber ") ArrayList getBenHealthDetails(@Param("healthIdNumber") String healthIdNumber); + // Same rows FHIR-API getBenhealthID reads, so the worklist can fill healthId/healthIdNumber without an HTTP call + @Query(nativeQuery = true, value = " SELECT HealthID, HealthIdNumber FROM db_iemr.m_benhealthidmapping WHERE BeneficiaryRegID = :benRegId ") + List getHealthIdMappingRows(@Param("benRegId") Long benRegId); + + @Query(nativeQuery = true, value = " SELECT HealthId FROM db_iemr.t_healthid WHERE HealthIdNumber = :healthIdNumber ") + List getHealthIdByNumber(@Param("healthIdNumber") String healthIdNumber); + // benRegId has no unique constraint on i_beneficiarymapping — a beneficiary can have // more than one mapping row, so this must return a list, not assume a single result. @Query("SELECT b FROM RMNCHMBeneficiarymapping b WHERE b.benRegId = :benRegId ORDER BY b.benMapId DESC") diff --git a/src/main/java/com/iemr/flw/repo/iemr/DiagnosticOrderRepo.java b/src/main/java/com/iemr/flw/repo/iemr/DiagnosticOrderRepo.java index fd7c72892..36ecc6420 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/DiagnosticOrderRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/DiagnosticOrderRepo.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import java.sql.Timestamp; import java.util.List; import java.util.Optional; @@ -16,11 +17,8 @@ public interface DiagnosticOrderRepo extends JpaRepository findByExternalOrderId(String externalOrderId); - @Query("SELECT o FROM DiagnosticOrder o WHERE o.beneficiaryId = :beneficiaryId AND o.visitCode = :visitCode " + - "AND o.orderType = :orderType AND o.deleted = false") - Optional findByBeneficiaryIdAndVisitCodeAndOrderType(@Param("beneficiaryId") Long beneficiaryId, - @Param("visitCode") Long visitCode, - @Param("orderType") String orderType); + Optional findFirstByBeneficiaryIdAndVisitCodeAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc( + Long beneficiaryId, Long visitCode, String orderType); Optional findFirstByBeneficiaryIdAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc( Long beneficiaryId, String orderType); @@ -40,14 +38,24 @@ Optional findFirstByBeneficiaryIdAndOrderTypeAndDeletedFalseOrd "ORDER BY o.lastPolledAt ASC NULLS FIRST") List findTrueNatDueForPoll(); - @Query("SELECT o FROM DiagnosticOrder o WHERE o.status IN ('PENDING', 'IN_PROGRESS') AND o.deleted = false") - List findAllOutstandingOrders(); + // The (disabled) daily close only touches orders created within [dayStart, dayEnd) — i.e. today's. + @Query("SELECT o FROM DiagnosticOrder o WHERE o.status IN ('PENDING', 'IN_PROGRESS') AND o.deleted = false " + + "AND o.createdDate >= :dayStart AND o.createdDate < :dayEnd") + List findAllOutstandingOrders(@Param("dayStart") Timestamp dayStart, @Param("dayEnd") Timestamp dayEnd); @Transactional @Modifying @Query("UPDATE DiagnosticOrder o SET o.vanSerialNo = o.id WHERE o.id = :id") void updateVanSerialNo(@Param("id") Long id); + // A poll that changed nothing only records when it ran (and the retry count), leaving processed, + // modified_by and the rest of the row alone: no re-upload to central, no change-log line. + @Transactional + @Modifying + @Query("UPDATE DiagnosticOrder o SET o.lastPolledAt = :polledAt, o.retryCount = :retryCount WHERE o.id = :id") + int recordUnchangedPoll(@Param("id") Long id, @Param("polledAt") Timestamp polledAt, + @Param("retryCount") Integer retryCount); + // Beneficiary-status-summary queries, filtered the same way as // FormResponseRepo.findBeneficiaryIdsByFormIdAndStatusFiltered - null-safe optional // villageId/providerServiceMapId via a correlated BenFlowStatus subquery. @@ -55,7 +63,7 @@ Optional findFirstByBeneficiaryIdAndOrderTypeAndDeletedFalseOrd // beneficiary with an old terminal order and a new in-flight retest of the same orderType // is bucketed only by the retest, not both. @Query("SELECT o.beneficiaryId FROM DiagnosticOrder o WHERE o.orderType = :orderType AND o.deleted = false " + - "AND o.status NOT IN ('COMPLETED', 'EXPIRED', 'FAILED', 'REFUSED', 'MANUAL_ENTRY') " + + "AND o.status IN ('PENDING', 'IN_PROGRESS') " + "AND o.id = (SELECT MAX(o2.id) FROM DiagnosticOrder o2 " + "WHERE o2.beneficiaryId = o.beneficiaryId AND o2.orderType = :orderType AND o2.deleted = false) " + "AND o.beneficiaryId IN (SELECT b.beneficiaryID FROM BenFlowStatus b WHERE b.deleted = false " + @@ -75,42 +83,44 @@ List findBeneficiaryIdsCompleted(@Param("orderType") String orderType, @Param("villageId") Integer villageId, @Param("providerServiceMapId") Integer providerServiceMapId); @Query("SELECT o.beneficiaryId FROM DiagnosticOrder o WHERE o.orderType = :orderType AND o.deleted = false " + - "AND o.status = 'EXPIRED' " + + "AND o.status = 'FAILED' " + "AND o.id = (SELECT MAX(o2.id) FROM DiagnosticOrder o2 " + "WHERE o2.beneficiaryId = o.beneficiaryId AND o2.orderType = :orderType AND o2.deleted = false) " + "AND o.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 findBeneficiaryIdsPollingTimedOut(@Param("orderType") String orderType, + List findBeneficiaryIdsFailed(@Param("orderType") String orderType, @Param("villageId") Integer villageId, @Param("providerServiceMapId") Integer providerServiceMapId); @Query("SELECT o.beneficiaryId FROM DiagnosticOrder o WHERE o.orderType = :orderType AND o.deleted = false " + - "AND o.status = 'FAILED' " + + "AND o.status IN ('CLOSED', 'CANCELLED', 'EXPIRED', 'REFUSED') " + "AND o.id = (SELECT MAX(o2.id) FROM DiagnosticOrder o2 " + "WHERE o2.beneficiaryId = o.beneficiaryId AND o2.orderType = :orderType AND o2.deleted = false) " + "AND o.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 findBeneficiaryIdsFailed(@Param("orderType") String orderType, + List findBeneficiaryIdsClosed(@Param("orderType") String orderType, @Param("villageId") Integer villageId, @Param("providerServiceMapId") Integer providerServiceMapId); @Query("SELECT o.beneficiaryId FROM DiagnosticOrder o WHERE o.orderType = :orderType AND o.deleted = false " + - "AND o.status = 'REFUSED' " + + "AND o.status = 'MANUAL_ENTRY' " + "AND o.id = (SELECT MAX(o2.id) FROM DiagnosticOrder o2 " + "WHERE o2.beneficiaryId = o.beneficiaryId AND o2.orderType = :orderType AND o2.deleted = false) " + "AND o.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 findBeneficiaryIdsRefused(@Param("orderType") String orderType, + List findBeneficiaryIdsAwaitingManualEntry(@Param("orderType") String orderType, @Param("villageId") Integer villageId, @Param("providerServiceMapId") Integer providerServiceMapId); - @Query("SELECT o.beneficiaryId FROM DiagnosticOrder o WHERE o.orderType = :orderType AND o.deleted = false " + - "AND o.status = 'MANUAL_ENTRY' " + + // The five queries above in one pass: beneficiaryId + status of each beneficiary's latest order, + // same filters, for the caller to bucket by status. + @Query("SELECT o.beneficiaryId, o.status FROM DiagnosticOrder o WHERE o.orderType = :orderType AND o.deleted = false " + + "AND o.status IN ('PENDING', 'IN_PROGRESS', 'COMPLETED', 'FAILED', 'CLOSED', 'CANCELLED', 'EXPIRED', 'REFUSED', 'MANUAL_ENTRY') " + "AND o.id = (SELECT MAX(o2.id) FROM DiagnosticOrder o2 " + "WHERE o2.beneficiaryId = o.beneficiaryId AND o2.orderType = :orderType AND o2.deleted = false) " + "AND o.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 findBeneficiaryIdsAwaitingManualEntry(@Param("orderType") String orderType, + List findLatestOrderStatusByBeneficiary(@Param("orderType") String orderType, @Param("villageId") Integer villageId, @Param("providerServiceMapId") Integer providerServiceMapId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/DynamicFormMigrationLogRepo.java b/src/main/java/com/iemr/flw/repo/iemr/DynamicFormMigrationLogRepo.java new file mode 100644 index 000000000..9f993076b --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/DynamicFormMigrationLogRepo.java @@ -0,0 +1,34 @@ +/* + * 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.repo.iemr; + +import com.iemr.flw.domain.iemr.DynamicFormMigrationLog; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * Repository for applied form-structure migration records. + * Id type is the migrationId String itself — existsById/save need no custom methods. + */ +@Repository +public interface DynamicFormMigrationLogRepo extends JpaRepository { +} 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 f389b5dec..c2abe9a0c 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/FormSectionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FormSectionRepo.java index 9f135959b..66192716c 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/FormSectionRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/FormSectionRepo.java @@ -24,12 +24,14 @@ import com.iemr.flw.domain.iemr.FormSection; import com.iemr.flw.masterEnum.SectionPhase; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.List; +import java.util.Optional; /** * Repository for form sections. @@ -40,6 +42,20 @@ public interface FormSectionRepo extends JpaRepository { List findByFormVersion_VersionIdOrderByDisplayOrderAsc(Long versionId); + /** Read-path variant excluding removed (isActive=false) sections. */ + List findByFormVersion_VersionIdAndIsActiveTrueOrderByDisplayOrderAsc(Long versionId); + + Optional findByFormVersion_VersionIdAndSectionUuid(Long versionId, String sectionUuid); + + Optional findTopByFormVersion_VersionIdOrderByDisplayOrderDesc(Long versionId); + + /** Shifts displayOrder by delta for every section in [from, to] within a version — used to make room for/close a gap around an inserted or moved sibling. */ + @Modifying(flushAutomatically = true, clearAutomatically = true) + @Query("UPDATE FormSection s SET s.displayOrder = s.displayOrder + :delta " + + "WHERE s.formVersion.versionId = :versionId AND s.displayOrder BETWEEN :from AND :to") + void shiftDisplayOrder(@Param("versionId") Long versionId, @Param("from") int from, + @Param("to") int to, @Param("delta") int delta); + @Query("SELECT fs.formVersion.versionId, COUNT(fs) FROM FormSection fs " + "WHERE fs.formVersion.versionId IN :versionIds " + "AND fs.sectionPhase = :sectionPhase " + 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 1d8583aea..e7a8c8ecd 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/OptionConditionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/OptionConditionRepo.java index 633418894..7ec5cad52 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/OptionConditionRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/OptionConditionRepo.java @@ -29,6 +29,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; /** * Repository for option conditions. @@ -38,6 +39,13 @@ public interface OptionConditionRepo extends JpaRepository findByQuestionOption_OptionId(Long optionId); + /** No surrogate natural key on conditions — matched by (actionType, target) within an option. */ + Optional findByQuestionOption_OptionIdAndActionTypeAndTargetQuestion_QuestionUuid( + Long optionId, String actionType, String targetQuestionUuid); + + Optional findByQuestionOption_OptionIdAndActionTypeAndTargetSection_SectionUuid( + Long optionId, String actionType, String targetSectionUuid); + @Query("SELECT oc.targetQuestion.questionId FROM OptionCondition oc " + "WHERE oc.questionOption.sectionQuestion.formSection.formVersion.versionId = :versionId " + "AND oc.targetQuestion IS NOT NULL") @@ -47,9 +55,11 @@ public interface OptionConditionRepo extends JpaRepository findByOptionIds(@Param("optionIds") Collection optionIds); } 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 f75120551..7b5b3418c 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java @@ -23,12 +23,14 @@ import com.iemr.flw.domain.iemr.QuestionOption; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.List; +import java.util.Optional; /** * Repository for question options. @@ -38,11 +40,30 @@ public interface QuestionOptionRepo extends JpaRepository List findBySectionQuestion_QuestionIdOrderByDisplayOrderAsc(Long questionId); + Optional findBySectionQuestion_QuestionIdAndOptionValue(Long questionId, String optionValue); + + Optional findTopBySectionQuestion_QuestionIdOrderByDisplayOrderDesc(Long questionId); + + /** Shifts displayOrder by delta for every option in [from, to] within a question — used to make room for/close a gap around an inserted or moved sibling. */ + @Modifying(flushAutomatically = true, clearAutomatically = true) + @Query("UPDATE QuestionOption o SET o.displayOrder = o.displayOrder + :delta " + + "WHERE o.sectionQuestion.questionId = :questionId AND o.displayOrder BETWEEN :from AND :to") + void shiftDisplayOrder(@Param("questionId") Long questionId, @Param("from") int from, + @Param("to") int to, @Param("delta") int delta); + /** * Loads all options for a set of questions in one query. * JOIN FETCH ensures sectionQuestion is hydrated so callers can group by questionId without extra queries. + * Excludes removed (isActive=false) options — used only by read paths; reconciliation matching + * uses the natural-key finder above, which must see inactive rows too. */ @Query("SELECT o FROM QuestionOption o JOIN FETCH o.sectionQuestion " - + "WHERE o.sectionQuestion.questionId IN :questionIds ORDER BY o.displayOrder ASC") + + "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/repo/iemr/QuestionValidationRepo.java b/src/main/java/com/iemr/flw/repo/iemr/QuestionValidationRepo.java index d1cf41876..17e1ea616 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/QuestionValidationRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/QuestionValidationRepo.java @@ -22,6 +22,7 @@ package com.iemr.flw.repo.iemr; import com.iemr.flw.domain.iemr.QuestionValidation; +import com.iemr.flw.masterEnum.ValidationType; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -29,6 +30,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; /** * Repository for question validation rules. @@ -38,11 +40,17 @@ public interface QuestionValidationRepo extends JpaRepository findBySectionQuestion_QuestionId(Long questionId); + /** No surrogate natural key on validations — matched by the (type, param) content tuple within a question. */ + Optional findBySectionQuestion_QuestionIdAndValidationTypeAndValidationParam( + Long questionId, ValidationType validationType, String validationParam); + /** * Loads all validations for a set of questions in one query. * JOIN FETCH ensures sectionQuestion is hydrated so callers can group by questionId without extra queries. + * Excludes removed (isActive=false) validations — used only by read paths; reconciliation matching + * uses the natural-key finder above, which must see inactive rows too. */ @Query("SELECT v FROM QuestionValidation v JOIN FETCH v.sectionQuestion " - + "WHERE v.sectionQuestion.questionId IN :questionIds") + + "WHERE v.sectionQuestion.questionId IN :questionIds AND v.isActive = true") List findByQuestionIds(@Param("questionIds") Collection questionIds); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/SectionQuestionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SectionQuestionRepo.java index 6a117e968..520993666 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/SectionQuestionRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/SectionQuestionRepo.java @@ -23,12 +23,14 @@ import com.iemr.flw.domain.iemr.SectionQuestion; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.List; +import java.util.Optional; /** * Repository for section questions. @@ -38,11 +40,27 @@ public interface SectionQuestionRepo extends JpaRepository findByFormSection_SectionIdOrderByDisplayOrderAsc(Long sectionId); + Optional findByFormSection_SectionIdAndQuestionUuid(Long sectionId, String questionUuid); + + /** Version-scoped lookup — a condition's target question may live in a different section of the same version. */ + Optional findByFormSection_FormVersion_VersionIdAndQuestionUuid(Long versionId, String questionUuid); + + Optional findTopByFormSection_SectionIdOrderByDisplayOrderDesc(Long sectionId); + + /** Shifts displayOrder by delta for every question in [from, to] within a section — used to make room for/close a gap around an inserted or moved sibling. */ + @Modifying(flushAutomatically = true, clearAutomatically = true) + @Query("UPDATE SectionQuestion q SET q.displayOrder = q.displayOrder + :delta " + + "WHERE q.formSection.sectionId = :sectionId AND q.displayOrder BETWEEN :from AND :to") + void shiftDisplayOrder(@Param("sectionId") Long sectionId, @Param("from") int from, + @Param("to") int to, @Param("delta") int delta); + /** * Loads all questions for a set of sections in one query. * JOIN FETCH ensures formSection is hydrated so callers can group by sectionId without extra queries. + * Excludes unlinked (isActive=false) questions — used only by read paths; reconciliation matching + * uses the natural-key finders above, which must see inactive rows too. */ @Query("SELECT q FROM SectionQuestion q JOIN FETCH q.formSection " - + "WHERE q.formSection.sectionId IN :sectionIds ORDER BY q.displayOrder ASC") + + "WHERE q.formSection.sectionId IN :sectionIds AND q.isActive = true ORDER BY q.displayOrder ASC") List findBySectionIdsOrderByDisplayOrderAsc(@Param("sectionIds") Collection sectionIds); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/StopTBDiagnosticsRepo.java b/src/main/java/com/iemr/flw/repo/iemr/StopTBDiagnosticsRepo.java index de3fa9096..19bb9acfa 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/StopTBDiagnosticsRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/StopTBDiagnosticsRepo.java @@ -4,6 +4,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.QueryHints; +import jakarta.persistence.QueryHint; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -19,6 +21,8 @@ public interface StopTBDiagnosticsRepo extends JpaRepository findAllByProviderServiceMapID(@Param("psmId") Integer psmId); + // Read-only: getAll only reads these rows, so Hibernate keeps no change-tracking snapshot per row + @QueryHints(@QueryHint(name = "org.hibernate.readOnly", value = "true")) @Query("SELECT d FROM StopTBDiagnostics d WHERE d.benRegID IN " + "(SELECT b.beneficiaryRegID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId) " + "AND d.deleted = false ORDER BY d.visitDate DESC") diff --git a/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralExaminationRepo.java b/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralExaminationRepo.java index 944e99a65..798fcaf85 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralExaminationRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralExaminationRepo.java @@ -5,6 +5,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.QueryHints; +import jakarta.persistence.QueryHint; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -32,6 +34,8 @@ StopTBGeneralExamination findByBeneficiaryRegIDAndVisitCode(@Param("beneficiaryR @Query("SELECT e FROM StopTBGeneralExamination e WHERE e.providerServiceMapID = :psmId AND e.deleted = false ORDER BY e.createdDate DESC") List findAllByProviderServiceMapID(@Param("psmId") Integer psmId); + // Read-only: getAll only reads these rows, so Hibernate keeps no change-tracking snapshot per row + @QueryHints(@QueryHint(name = "org.hibernate.readOnly", value = "true")) @Query("SELECT e FROM StopTBGeneralExamination e WHERE e.beneficiaryRegID IN " + "(SELECT b.beneficiaryRegID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId) " + "AND e.deleted = false ORDER BY e.createdDate DESC") diff --git a/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralOpdRepo.java b/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralOpdRepo.java index 3cb8868f8..d35925a26 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralOpdRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralOpdRepo.java @@ -5,6 +5,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.QueryHints; +import jakarta.persistence.QueryHint; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -30,6 +32,8 @@ public interface StopTBGeneralOpdRepo extends JpaRepository findAllByProviderServiceMapID(@Param("psmId") Integer psmId); + // Read-only: getAll only reads these rows, so Hibernate keeps no change-tracking snapshot per row + @QueryHints(@QueryHint(name = "org.hibernate.readOnly", value = "true")) @Query("SELECT o FROM StopTBGeneralOpd o WHERE o.benRegID IN " + "(SELECT b.beneficiaryRegID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId) " + "AND o.deleted = false ORDER BY o.createdDate DESC") diff --git a/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java b/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java index f656dc91d..cfb0665db 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java @@ -5,6 +5,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.QueryHints; +import jakarta.persistence.QueryHint; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -37,6 +39,8 @@ public interface TBScreeningRepo extends JpaRepository { @Query("SELECT tbs FROM TBScreening tbs WHERE tbs.providerServiceMapID = :psmId AND tbs.deleted = false ORDER BY tbs.visitDate DESC") List findAllByProviderServiceMapID(@Param("psmId") Integer psmId); + // Read-only: getAll only reads these rows, so Hibernate keeps no change-tracking snapshot per row + @QueryHints(@QueryHint(name = "org.hibernate.readOnly", value = "true")) @Query("SELECT tbs FROM TBScreening tbs WHERE tbs.benRegID IN " + "(SELECT b.beneficiaryRegID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId) " + "AND tbs.deleted = false ORDER BY tbs.visitDate DESC") diff --git a/src/main/java/com/iemr/flw/repo/iemr/TBSuspectedRepo.java b/src/main/java/com/iemr/flw/repo/iemr/TBSuspectedRepo.java index 3df494fa4..277d21fd6 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/TBSuspectedRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/TBSuspectedRepo.java @@ -29,8 +29,11 @@ TBSuspected getByUserIdAndBenIdAndVisitCode(@Param("benId") Long benId, @Param(" @Query("SELECT tbs FROM TBSuspected tbs WHERE tbs.userId = :userId and tbs.visitDate >= :fromDate and tbs.visitDate <= :toDate") List getByUserId(@Param("userId") Integer userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); - @Query("SELECT tbs FROM TBSuspected tbs WHERE tbs.benId IN " + - "(SELECT b.beneficiaryID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId)") + // Same query as before in SQL, with an optimizer hint so the village subquery reads + // idx_flow_psm_village_reg instead of the PSM-only index (ignored if that index is missing). + @Query(nativeQuery = true, value = "SELECT t.* FROM db_iemr.tb_suspected t WHERE t.ben_id IN " + + "(SELECT /*+ INDEX(b idx_flow_psm_village_reg) */ b.beneficiary_id FROM db_iemr.i_ben_flow_outreach b " + + "WHERE b.providerServiceMapID = :psmId AND b.villageID = :villageId)") List getByProviderServiceMapIdAndVillageId(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); @Transactional diff --git a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java index 354088892..d2cdc2f46 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java @@ -36,10 +36,47 @@ public interface UserServiceRoleRepo extends JpaRepository getUserRolesByIds(@Param("userIds") List userIds); + @Query(value = "SELECT d.DistrictID, d.DistrictName FROM m_districtblock db " + + "JOIN m_district d ON d.DistrictID = db.DistrictID " + + "WHERE db.BlockID = :blockId LIMIT 1", nativeQuery = true) + List getDistrictByBlockId(@Param("blockId") Integer blockId); + + // Stop TB / Nikshay — additive only. Reads m_userservicerolemapping directly + // (NOT the shared v_userservicerolemapping view) so the view stays untouched + // and no other service line's query is affected. Returns nothing for any + // user whose rows don't have NikshayTUID set (i.e. every non-Stop-TB user). + // NikshayTUID/NikshayFacilityID are TEXT columns holding a comma-joined list + // of IDs (e.g. "12,45,78"), not a single ID. Name resolution against + // m_nikshay_tu/m_nikshay_facility is done in Java (see UserServiceImpl) via + // an indexed IN(...) lookup on their primary keys, instead of joining here + // with FIND_IN_SET — FIND_IN_SET can't use an index on either side, so it + // forces a full scan of the master table per call (measured: ~60s against + // m_nikshay_facility's 300k+ rows for a user with ~100 mapped facilities). + @Query(value = "SELECT usrm.NikshayTUID, usrm.NikshayFacilityID, usrm.DistrictID " + + "FROM m_userservicerolemapping usrm " + + "WHERE usrm.UserID = :userId AND usrm.ProviderServiceMapID = :providerServiceMapId " + + "AND usrm.Deleted = false AND usrm.NikshayTUID IS NOT NULL", + nativeQuery = true) + List getNikshayMappingRows(@Param("userId") Integer userId, + @Param("providerServiceMapId") Integer providerServiceMapId); + + // Every active mapping row's service and village list, for the STOP-TB changes feed's scope check. + @Query(value = "SELECT usrm.ProviderServiceMapID, usrm.Villageid FROM m_userservicerolemapping usrm " + + "WHERE usrm.UserID = :userId AND usrm.Deleted = false", nativeQuery = true) + List getServiceVillageRows(@Param("userId") Integer userId); + + @Query(value = "SELECT NikshayTUID, TUName FROM m_nikshay_tu WHERE NikshayTUID IN (:ids)", nativeQuery = true) + List findNikshayTuNames(@Param("ids") java.util.Collection ids); + + @Query(value = "SELECT NikshayFacilityID, FacilityName FROM m_nikshay_facility WHERE NikshayFacilityID IN (:ids)", nativeQuery = true) + List findNikshayFacilityNames(@Param("ids") java.util.Collection ids); + + // DistrictID on m_userservicerolemapping is a Nikshay district ID, not an + // AMRIT one (see setWorkLocationObject in Admin-UI) - resolving its name + // against m_nikshay_district (the same ID space) is safe, unlike joining it + // against AMRIT's own m_district, which would silently match whatever AMRIT + // district happens to share that same numeric ID by coincidence. + @Query(value = "SELECT DistrictName FROM m_nikshay_district WHERE NikshayDistrictID = :id", nativeQuery = true) + String findNikshayDistrictName(@Param("id") Integer id); } diff --git a/src/main/java/com/iemr/flw/seeder/migration/DynamicFormMigrationApplier.java b/src/main/java/com/iemr/flw/seeder/migration/DynamicFormMigrationApplier.java new file mode 100644 index 000000000..ae4de9c6e --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/DynamicFormMigrationApplier.java @@ -0,0 +1,49 @@ +/* + * 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.DynamicFormMigrationLog; +import com.iemr.flw.repo.iemr.DynamicFormMigrationLogRepo; +import com.iemr.flw.service.DynamicFormReconciliationService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * Applies one {@link FormStructureMigration} and records it as applied, as a single atomic unit. + * Kept as its own bean (rather than a method on {@link DynamicFormMigrationRunner}) so the + * {@code @Transactional} proxy is actually honored — a runner calling this method on itself would + * bypass Spring AOP's self-invocation limitation. + */ +@Service +@RequiredArgsConstructor +public class DynamicFormMigrationApplier { + + private final DynamicFormReconciliationService reconciliationService; + private final DynamicFormMigrationLogRepo migrationLogRepo; + + @Transactional + public void apply(FormStructureMigration migration) { + migration.apply(reconciliationService); + migrationLogRepo.save(new DynamicFormMigrationLog(migration.migrationId(), null)); + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/DynamicFormMigrationRunner.java b/src/main/java/com/iemr/flw/seeder/migration/DynamicFormMigrationRunner.java new file mode 100644 index 000000000..2071b61ed --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/DynamicFormMigrationRunner.java @@ -0,0 +1,73 @@ +/* + * 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.repo.iemr.DynamicFormMigrationLogRepo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import java.util.Comparator; +import java.util.List; + +/** + * Applies every {@link FormStructureMigration} bean, in {@link FormStructureMigration#migrationId()} + * order, skipping ones already recorded in {@code t_dynamic_form_migration_log}. + * + * Runs as an {@link ApplicationRunner} rather than another {@code @PostConstruct} specifically so it + * always runs after the 6 form seeders: Spring Boot invokes ApplicationRunners only once the whole + * application context has finished refreshing, which is strictly after every bean's + * {@code @PostConstruct} (the seeders included) has already completed — no {@code @Order} + * coordination needed between the two mechanisms. + * + * A migration that throws propagates out of this loop and aborts startup — a broken migration + * should fail loudly, not be silently skipped, and later migrations shouldn't apply out of order + * behind a failed one. + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class DynamicFormMigrationRunner implements ApplicationRunner { + + private final List migrations; + private final DynamicFormMigrationLogRepo migrationLogRepo; + private final DynamicFormMigrationApplier applier; + + @Override + public void run(ApplicationArguments args) { + migrations.stream() + .sorted(Comparator.comparing(FormStructureMigration::migrationId)) + .forEach(this::applyIfNeeded); + } + + private void applyIfNeeded(FormStructureMigration migration) { + String id = migration.migrationId(); + if (migrationLogRepo.existsById(id)) { + log.info("Form structure migration '{}' already applied — skipping.", id); + return; + } + applier.apply(migration); + log.info("Form structure migration '{}' applied.", id); + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/FormStructureMigration.java b/src/main/java/com/iemr/flw/seeder/migration/FormStructureMigration.java new file mode 100644 index 000000000..969bb04f3 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/FormStructureMigration.java @@ -0,0 +1,78 @@ +/* + * 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.service.DynamicFormReconciliationService; + +/** + * One incremental, one-off structural change to a form that has already been created by one of the + * {@code com.iemr.flw.seeder} classes — e.g. "add this new question to that existing section", or + * "add this new option to that existing question". {@code DynamicFormMigrationRunner} discovers + * every Spring bean implementing this interface, sorts them by {@link #migrationId()}, and applies + * each exactly once, recording it in {@code t_dynamic_form_migration_log} so it is skipped on + * every later restart. A migration should never be edited after it has shipped — write a new one + * instead — since the log only records "has this id run", not what it actually did. + * + * Naming convention: {@code V_ShortDescription}, e.g. {@code V001_AddSideEffectsQuestion}, + * zero-padded so lexicographic sort matches numeric order. Give each class a javadoc stating the + * business reason for the change — that, plus the class itself, is the permanent changelog. + * + * Example: + *
{@code
+ * @Component
+ * public class V001_AddSideEffectsQuestionToTbCounselling implements FormStructureMigration {
+ *
+ *     @Override
+ *     public String migrationId() {
+ *         return "V001";
+ *     }
+ *
+ *     @Override
+ *     public void apply(DynamicFormReconciliationService svc) {
+ *         FormVersion version = svc.latestVersion("TB_COUNSELLING")
+ *                 .orElseThrow(() -> new IllegalStateException(
+ *                         "TB_COUNSELLING not found — must run after TbCounsellingFormSeeder"));
+ *         FormSection section = svc.section(version, "TB_SEC_B")
+ *                 .orElseThrow(() -> new IllegalStateException("Section TB_SEC_B not found"));
+ *
+ *         SectionQuestionDTO question = new SectionQuestionDTO();
+ *         question.setQuestionUuid("TB_B_Q7");
+ *         question.setQuestionText("Side effects reported?");
+ *         question.setQuestionType(QuestionType.RADIO);
+ *         question.setOptions(List.of(yesOption, noOption));
+ *         svc.ensureQuestion(section, question);
+ *     }
+ * }
+ * }
+ */ +public interface FormStructureMigration { + + /** Stable id, e.g. "V001" — the migration-log primary key and the sort key for apply order. Never change it once shipped. */ + String migrationId(); + + /** + * Applies this migration's change(s) via the reconciliation service's ensureX methods. + * Should remain safe to re-run (ensureX no-ops on rows that already exist) even though the + * runner normally calls this only once per migrationId, per the tracking log. + */ + void apply(DynamicFormReconciliationService reconciliationService); +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V001_1_CreateContactTracingVersion2.java b/src/main/java/com/iemr/flw/seeder/migration/V001_1_CreateContactTracingVersion2.java new file mode 100644 index 000000000..78c7cd645 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V001_1_CreateContactTracingVersion2.java @@ -0,0 +1,108 @@ +/* + * 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.FormVersion; +import com.iemr.flw.dto.iemr.DynamicFormDTO; +import com.iemr.flw.dto.iemr.FormSectionDTO; +import com.iemr.flw.dto.iemr.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.service.DynamicFormDefinitionService; +import com.iemr.flw.service.DynamicFormReconciliationService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Clones the seeded version 1 of both contact tracing forms — Community Contact Tracing and + * Occupational Contact Tracing — into a new version 2, so the later structural changes to them are + * applied to version 2 only and version 1 stays exactly as the seeders created it: + * COMMUNITY_CONTACT_TRACING (V002, V003, V006, V007, V008) and OCCUPATION_CONTACT_TRACING (V002, V004, + * V005). Responses keep the versionId they were submitted against; new responses and the app use the + * latest version. + * + * Id "V001_1" sorts between V001 and V002, so this runs before the first migration that touches + * either form — every migration resolves a form via {@code latestVersion}, which is version 2 from + * here on. + * + * Uses {@link DynamicFormDefinitionService#updateForm}, which copies every section, question, option, + * validation and condition into a new version and marks the current one isLatest=false. All ids are + * cleared from the version-1 DTO first: the mapper copies them onto the new entities, and saving an + * entity with an existing id would move that version-1 row into version 2 instead of copying it. + * Conditions are re-wired by targetQuestionUuid/targetSectionUuid, which are kept. + */ +@Component +@RequiredArgsConstructor +public class V001_1_CreateContactTracingVersion2 implements FormStructureMigration { + + private static final List FORM_UUIDS = List.of( + "COMMUNITY_CONTACT_TRACING", + "OCCUPATION_CONTACT_TRACING"); + + private final DynamicFormDefinitionService definitionService; + + @Override + public String migrationId() { + return "V001_1"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + FORM_UUIDS.forEach(formUuid -> createVersion2(svc, formUuid)); + } + + private void createVersion2(DynamicFormReconciliationService svc, String formUuid) { + FormVersion latest = svc.latestVersion(formUuid) + .orElseThrow(() -> new IllegalStateException(formUuid + " not found — must run after its seeder")); + if (latest.getVersionNumber() > 1) { + return; + } + + Long formId = latest.getDynamicForm().getFormId(); + DynamicFormDTO version1 = definitionService.getFormDefinition(formId); + clearIds(version1); + definitionService.updateForm(formId, version1); + } + + private void clearIds(DynamicFormDTO form) { + for (FormSectionDTO section : form.getSections()) { + section.setSectionId(null); + for (SectionQuestionDTO question : section.getQuestions()) { + question.setQuestionId(null); + for (QuestionValidationDTO validation : question.getValidations()) { + validation.setValidationId(null); + } + for (QuestionOptionDTO option : question.getOptions()) { + option.setOptionId(null); + for (OptionConditionDTO condition : option.getConditions()) { + condition.setConditionId(null); + condition.setTargetQuestionId(null); + condition.setTargetSectionId(null); + } + } + } + } + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V001_ReplaceTfuAdrOptions.java b/src/main/java/com/iemr/flw/seeder/migration/V001_ReplaceTfuAdrOptions.java new file mode 100644 index 000000000..6fc90ff6e --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V001_ReplaceTfuAdrOptions.java @@ -0,0 +1,104 @@ +/* + * 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.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.service.DynamicFormReconciliationService; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Replaces the TPT Follow Up form's "Adverse Drug Reactions" (TFU_ADR) option list with the + * clinically revised set of symptoms, per the updated ADR checklist supplied for this form. + * + * 7 of the 24 existing options already match the new list exactly (same wording) and are left + * untouched by {@code ensureOption}'s natural-key match: NAUSEA, VOMITING, ABDOMINAL_PAIN, + * DARK_COLOUR_URINE, ITCHING, TINGLING_BURNING_NUMBNESS_HANDS_FEET, FLU_LIKE_SYNDROME. The other + * 17 old options are no longer part of the revised list and are soft-removed (never hard-deleted — + * historical responses may reference them); the 13 new options are added. + */ +@Component +public class V001_ReplaceTfuAdrOptions implements FormStructureMigration { + + private static final List REMOVED_OPTION_VALUES = List.of( + "UNKNOWN", + "FLU_LIKE_SYNDROME_WITH_DIZZINESS_HEADACHE", + "YELLOWISH_DISCOLORATION_SKIN_EYES", + "DISCOLORATION_BODY_FLUIDS", + "PALE_STOOL", + "SKIN_RASH", + "SLEEPINESS_LETHARGY", + "PERSISTENT_UNFORMED_WATERY_STOOLS", + "MENTAL_CHANGES_SIGNS_BLEEDING", + "CONVULSIONS", + "ANAEMIA", + "ARTHRALGIA", + "DECREASED_APPETITE", + "HYPOTENSION_SYNCOPE", + "CONJUCTIVITIES", + "SHOCK", + "NONE_REPORTED"); + + @Override + public String migrationId() { + return "V001"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + FormVersion version = svc.latestVersion("TPT_FOLLOW_UP") + .orElseThrow(() -> new IllegalStateException( + "TPT_FOLLOW_UP not found — must run after TptFollowUpFormSeeder")); + FormSection section = svc.section(version, "TFU_SEC_2") + .orElseThrow(() -> new IllegalStateException("Section TFU_SEC_2 not found")); + SectionQuestion question = svc.question(section, "TFU_ADR") + .orElseThrow(() -> new IllegalStateException("Question TFU_ADR not found")); + + REMOVED_OPTION_VALUES.forEach(value -> svc.option(question, value) + .ifPresent(opt -> svc.removeOption(opt.getOptionId()))); + + addOption(svc, question, "Yellowness of Skin", "YELLOWNESS_OF_SKIN"); + addOption(svc, question, "Loose motions >4 times in a day", "LOOSE_MOTIONS_GT4_PER_DAY"); + addOption(svc, question, "Rashes", "RASHES"); + addOption(svc, question, "Pain in Joints", "PAIN_IN_JOINTS"); + addOption(svc, question, "Impaired vision: Pain, Blurring of vision, Disturbance in colour vision", "IMPAIRED_VISION"); + addOption(svc, question, "Swelling of face or legs, Less or no urine", "SWELLING_FACE_LEGS_LESS_NO_URINE"); + addOption(svc, question, "Seeing abnormal things, changes of thoughts, suicidal thoughts", "ABNORMAL_THOUGHTS_SUICIDAL"); + addOption(svc, question, "Tiredness, lethargy, headache, giddiness, pale look, palpitations", "TIREDNESS_LETHARGY_GIDDINESS_PALPITATIONS"); + addOption(svc, question, "Ringing in ears, Loss of hearing, dizziness and loss of balance leading to recurrent fall", "TINNITUS_HEARING_LOSS_DIZZINESS_FALL"); + addOption(svc, question, "Slowness of activities, Swelling of face or neck, dis-appropriate weight gain", "SLOWNESS_FACIAL_NECK_SWELLING_WEIGHT_GAIN"); + addOption(svc, question, "Pain and swelling in muscles and Tendons, difficulty in movement", "MUSCLE_TENDON_PAIN_SWELLING"); + addOption(svc, question, "Convulsion", "CONVULSION"); + addOption(svc, question, "Orange and red color of urine, sweat, sputum, saliva or tears", "ORANGE_RED_DISCOLORATION_BODY_FLUIDS"); + } + + private void addOption(DynamicFormReconciliationService svc, SectionQuestion question, String label, String value) { + QuestionOptionDTO dto = new QuestionOptionDTO(); + dto.setOptionLabel(label); + dto.setOptionValue(value); + svc.ensureOption(question, dto); + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V002_RenameNoOfContactsQuestion.java b/src/main/java/com/iemr/flw/seeder/migration/V002_RenameNoOfContactsQuestion.java new file mode 100644 index 000000000..836c1b1e3 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V002_RenameNoOfContactsQuestion.java @@ -0,0 +1,83 @@ +/* + * 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.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.service.DynamicFormReconciliationService; +import org.springframework.stereotype.Component; + +/** + * Renames the "No. of contacts" question to "Total No. of contacts" (and its Hindi translation) + * in both the Community Contact Tracing (CCT_NO_OF_CONTACTS) and Occupational Contact Tracing + * (OCT_NO_OF_CONTACTS) forms, per the revised field-label wording supplied for these forms. + * + * Only the label text changes — type, mandatoriness and position are read off the existing row + * and passed back unchanged, since {@code updateQuestion} overwrites all of its scalar fields + * unconditionally. + */ +@Component +public class V002_RenameNoOfContactsQuestion implements FormStructureMigration { + + private static final String NEW_TEXT = "Total No. of contacts"; + private static final String NEW_TEXT_HINDI = "कुल संपर्कों की संख्या"; + + @Override + public String migrationId() { + return "V002"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + renameQuestion(svc, "COMMUNITY_CONTACT_TRACING", "CCT_SEC_1", "CCT_NO_OF_CONTACTS"); + renameQuestion(svc, "OCCUPATION_CONTACT_TRACING", "OCT_SEC_1", "OCT_NO_OF_CONTACTS"); + } + + private void renameQuestion(DynamicFormReconciliationService svc, String formUuid, String sectionUuid, + String questionUuid) { + FormVersion version = svc.latestVersion(formUuid) + .orElseThrow(() -> new IllegalStateException( + formUuid + " not found — must run after its seeder")); + FormSection section = svc.section(version, sectionUuid) + .orElseThrow(() -> new IllegalStateException("Section " + sectionUuid + " not found")); + SectionQuestion question = svc.question(section, questionUuid) + .orElseThrow(() -> new IllegalStateException("Question " + questionUuid + " not found")); + + if (NEW_TEXT.equals(question.getQuestionText()) && NEW_TEXT_HINDI.equals(question.getQuestionTextHindi())) { + return; + } + + SectionQuestionDTO dto = new SectionQuestionDTO(); + dto.setQuestionText(NEW_TEXT); + dto.setQuestionTextHindi(NEW_TEXT_HINDI); + dto.setQuestionType(question.getQuestionType()); + dto.setIsMandatory(question.getIsMandatory()); + dto.setMaxLength(question.getMaxLength()); + dto.setDefaultValue(question.getDefaultValue()); + dto.setContainsPii(question.getContainsPii()); + dto.setDisplayOrder(question.getDisplayOrder()); + + svc.updateQuestion(question.getQuestionId(), dto); + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V003_ChangeExposureSettingToDropdownMulti.java b/src/main/java/com/iemr/flw/seeder/migration/V003_ChangeExposureSettingToDropdownMulti.java new file mode 100644 index 000000000..ba69d37b4 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V003_ChangeExposureSettingToDropdownMulti.java @@ -0,0 +1,76 @@ +/* + * 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.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.service.DynamicFormReconciliationService; +import org.springframework.stereotype.Component; + +/** + * Changes the Community Contact Tracing form's "Place of exposure" question (CCT_EXPOSURE_SETTING) + * from CHECKBOX_MULTI to DROPDOWN_MULTI, so the 12 place options render as a multi-select dropdown + * instead of a long checkbox list. + * + * Both types submit {@code optionValues} and store one response row per selected option, so + * existing responses remain valid. Options and the OTHER_PLACE → CCT_EXPOSURE_SETTING_OTHER + * conditional rule are untouched. All other scalar fields are read off the existing row and passed + * back unchanged, since {@code updateQuestion} overwrites all of them unconditionally. + */ +@Component +public class V003_ChangeExposureSettingToDropdownMulti implements FormStructureMigration { + + @Override + public String migrationId() { + return "V003"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + FormVersion version = svc.latestVersion("COMMUNITY_CONTACT_TRACING") + .orElseThrow(() -> new IllegalStateException( + "COMMUNITY_CONTACT_TRACING not found — must run after CommunityContactTracingFormSeeder")); + FormSection section = svc.section(version, "CCT_SEC_1") + .orElseThrow(() -> new IllegalStateException("Section CCT_SEC_1 not found")); + SectionQuestion question = svc.question(section, "CCT_EXPOSURE_SETTING") + .orElseThrow(() -> new IllegalStateException("Question CCT_EXPOSURE_SETTING not found")); + + if (question.getQuestionType() == QuestionType.DROPDOWN_MULTI) { + return; + } + + SectionQuestionDTO dto = new SectionQuestionDTO(); + dto.setQuestionText(question.getQuestionText()); + dto.setQuestionTextHindi(question.getQuestionTextHindi()); + dto.setQuestionType(QuestionType.DROPDOWN_MULTI); + dto.setIsMandatory(question.getIsMandatory()); + dto.setMaxLength(question.getMaxLength()); + dto.setDefaultValue(question.getDefaultValue()); + dto.setContainsPii(question.getContainsPii()); + dto.setDisplayOrder(question.getDisplayOrder()); + + svc.updateQuestion(question.getQuestionId(), dto); + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V004_ChangeOccupationToDropdown.java b/src/main/java/com/iemr/flw/seeder/migration/V004_ChangeOccupationToDropdown.java new file mode 100644 index 000000000..24db1f454 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V004_ChangeOccupationToDropdown.java @@ -0,0 +1,76 @@ +/* + * 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.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.service.DynamicFormReconciliationService; +import org.springframework.stereotype.Component; + +/** + * Changes the Occupational Contact Tracing form's "Occupation" question (OCT_OCCUPATION) from RADIO + * to DROPDOWN, so the 11 occupation options render as a single-select dropdown instead of a long + * radio list. + * + * Both types submit a single {@code optionValue} and store one response row, so existing responses + * remain valid. Options and their conditional rules (address questions, OTHER_OCCUPATION → + * OCT_OCCUPATION_OTHER) are untouched. All other scalar fields are read off the existing row and + * passed back unchanged, since {@code updateQuestion} overwrites all of them unconditionally. + */ +@Component +public class V004_ChangeOccupationToDropdown implements FormStructureMigration { + + @Override + public String migrationId() { + return "V004"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + FormVersion version = svc.latestVersion("OCCUPATION_CONTACT_TRACING") + .orElseThrow(() -> new IllegalStateException( + "OCCUPATION_CONTACT_TRACING not found — must run after OccupationalContactTracingFormSeeder")); + FormSection section = svc.section(version, "OCT_SEC_1") + .orElseThrow(() -> new IllegalStateException("Section OCT_SEC_1 not found")); + SectionQuestion question = svc.question(section, "OCT_OCCUPATION") + .orElseThrow(() -> new IllegalStateException("Question OCT_OCCUPATION not found")); + + if (question.getQuestionType() == QuestionType.DROPDOWN) { + return; + } + + SectionQuestionDTO dto = new SectionQuestionDTO(); + dto.setQuestionText(question.getQuestionText()); + dto.setQuestionTextHindi(question.getQuestionTextHindi()); + dto.setQuestionType(QuestionType.DROPDOWN); + dto.setIsMandatory(question.getIsMandatory()); + dto.setMaxLength(question.getMaxLength()); + dto.setDefaultValue(question.getDefaultValue()); + dto.setContainsPii(question.getContainsPii()); + dto.setDisplayOrder(question.getDisplayOrder()); + + svc.updateQuestion(question.getQuestionId(), dto); + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V005_AddAreaOfSharedSpaceQuestion.java b/src/main/java/com/iemr/flw/seeder/migration/V005_AddAreaOfSharedSpaceQuestion.java new file mode 100644 index 000000000..11a6a3d0c --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V005_AddAreaOfSharedSpaceQuestion.java @@ -0,0 +1,115 @@ +/* + * 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.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.masterEnum.ValidationType; +import com.iemr.flw.service.DynamicFormReconciliationService; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Adds an "Approximate Area of Shared Space" question to the Occupational Contact Tracing form, + * directly after "Type of Space" (OCT_TYPE_OF_SPACE), per the revised criteria for this form: + * enabled once a Type of Space is selected, whole square metres only, accepted range 50–5000. + * + * Mapped to Type of Space as a condition: hidden by default, and each of the 3 OCT_TYPE_OF_SPACE + * options reveals it (SHOW_QUESTION) and makes it mandatory (MANDATORY_IF) — conditions attach to + * options, so "any Type of Space selected" is one condition per option, all targeting this single + * question. Conventions used, since questions carry no dedicated fields for these: + * the helper text is stored in {@code defaultValue}, and the unit as a {@link ValidationType#UNIT} + * validation whose {@code validationParam} is the unit label. + * + * Inserted at display order 7 — {@code ensureQuestion} shifts "Daily duration of contact" to 8 and + * "Remarks" to 9. + */ +@Component +public class V005_AddAreaOfSharedSpaceQuestion implements FormStructureMigration { + + private static final String QUESTION_UUID = "OCT_AREA_OF_SHARED_SPACE"; + + private static final List TYPE_OF_SPACE_VALUES = List.of( + "OPEN_SPACE", + "CLOSED_SPACE_VENTILATED", + "CLOSED_SPACE_NOT_VENTILATED"); + + @Override + public String migrationId() { + return "V005"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + FormVersion version = svc.latestVersion("OCCUPATION_CONTACT_TRACING") + .orElseThrow(() -> new IllegalStateException( + "OCCUPATION_CONTACT_TRACING not found — must run after OccupationalContactTracingFormSeeder")); + FormSection section = svc.section(version, "OCT_SEC_1") + .orElseThrow(() -> new IllegalStateException("Section OCT_SEC_1 not found")); + SectionQuestion typeOfSpace = svc.question(section, "OCT_TYPE_OF_SPACE") + .orElseThrow(() -> new IllegalStateException("Question OCT_TYPE_OF_SPACE not found")); + + SectionQuestionDTO dto = new SectionQuestionDTO(); + dto.setQuestionUuid(QUESTION_UUID); + dto.setQuestionText("Approximate Area of Shared Space"); + dto.setQuestionTextHindi("साझा स्थान का अनुमानित क्षेत्रफल"); + dto.setQuestionType(QuestionType.NUMBER_PICKER); + dto.setDefaultValue("Give estimated measurement of area"); + dto.setIsMandatory(true); + dto.setDisplayOrder(7); + dto.setVisibleByDefault(false); + dto.setOptions(List.of()); + dto.setValidations(List.of()); + SectionQuestion area = svc.ensureQuestion(section, dto); + + svc.ensureValidation(area, validation(ValidationType.REGEX, + "^([5-9][0-9]|[1-9][0-9]{2}|[1-4][0-9]{3}|5000)$", "Enter a value between 50 and 5000.")); + svc.ensureValidation(area, validation(ValidationType.UNIT, "sq. m.", "Value is in sq. m.")); + + for (String value : TYPE_OF_SPACE_VALUES) { + svc.ensureValidation(area, validation(ValidationType.MANDATORY_IF, + "OCT_TYPE_OF_SPACE=" + value, "This field is mandatory")); + + QuestionOption option = svc.option(typeOfSpace, value) + .orElseThrow(() -> new IllegalStateException("Option OCT_TYPE_OF_SPACE=" + value + " not found")); + OptionConditionDTO show = new OptionConditionDTO(); + show.setActionType("SHOW_QUESTION"); + show.setTargetQuestionUuid(QUESTION_UUID); + svc.ensureCondition(option, show, version); + } + } + + private QuestionValidationDTO validation(ValidationType type, String param, String errorMessage) { + QuestionValidationDTO v = new QuestionValidationDTO(); + v.setValidationType(type); + v.setValidationParam(param); + v.setErrorMessage(errorMessage); + return v; + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V006_PerRelationshipTypeOfSpace.java b/src/main/java/com/iemr/flw/seeder/migration/V006_PerRelationshipTypeOfSpace.java new file mode 100644 index 000000000..822ea0867 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V006_PerRelationshipTypeOfSpace.java @@ -0,0 +1,172 @@ +/* + * 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.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.masterEnum.ValidationType; +import com.iemr.flw.service.DynamicFormReconciliationService; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Replaces the Community Contact Tracing form's single, standalone "Type of Space" question + * (CCT_TYPE_OF_SPACE) with one per "Relationship with community contacts" (CCT_RELATIONSHIP) + * option, each followed by its own "Approximate Area of Shared Space", so the exposure setting is + * captured per relationship type: + * + *
+ * CCT_RELATIONSHIP=<R> ─ SHOW_QUESTION ─► CCT_TYPE_OF_SPACE_<R>
+ *                                          └─ each option ─ SHOW_QUESTION ─► CCT_AREA_OF_SHARED_SPACE_<R>
+ * 
+ * + * The old CCT_TYPE_OF_SPACE is soft-removed (never hard-deleted — historical responses may + * reference it). The 14 new questions (a Type of Space / Area pair per relationship) are inserted + * into its slot, all hidden by default and mandatory only when revealed (MANDATORY_IF). Area + * questions follow V006's conventions: helper text in {@code defaultValue}, unit as a + * {@link ValidationType#UNIT} validation, whole square metres 50–5000. + */ +@Component +public class V006_PerRelationshipTypeOfSpace implements FormStructureMigration { + + private static final List RELATIONSHIP_VALUES = List.of( + "NEIGHBOUR", + "FRIEND", + "FELLOW_WORSHIPPER", + "FELLOW_COMMUTER", + "COMMUNITY_GROUP_MEMBER", + "FELLOW_PATIENT", + "OTHER"); + + /** {label, labelHindi, value} — same options as the retired CCT_TYPE_OF_SPACE. */ + private static final List TYPE_OF_SPACE_OPTIONS = List.of( + new String[] {"Open space", "खुला स्थान", "OPEN_SPACE"}, + new String[] {"Closed space with ventilation", "वेंटिलेशन के साथ बंद स्थान", "CLOSED_SPACE_VENTILATED"}, + new String[] {"Closed space with no ventilation", "बिना वेंटिलेशन के बंद स्थान", "CLOSED_SPACE_NOT_VENTILATED"}); + + private static final String AREA_REGEX = "^([5-9][0-9]|[1-9][0-9]{2}|[1-4][0-9]{3}|5000)$"; + private static final String MANDATORY_ERROR = "This field is mandatory"; + + @Override + public String migrationId() { + return "V006"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + FormVersion version = svc.latestVersion("COMMUNITY_CONTACT_TRACING") + .orElseThrow(() -> new IllegalStateException( + "COMMUNITY_CONTACT_TRACING not found — must run after CommunityContactTracingFormSeeder")); + FormSection section = svc.section(version, "CCT_SEC_1") + .orElseThrow(() -> new IllegalStateException("Section CCT_SEC_1 not found")); + SectionQuestion relationship = svc.question(section, "CCT_RELATIONSHIP") + .orElseThrow(() -> new IllegalStateException("Question CCT_RELATIONSHIP not found")); + SectionQuestion oldTypeOfSpace = svc.question(section, "CCT_TYPE_OF_SPACE") + .orElseThrow(() -> new IllegalStateException("Question CCT_TYPE_OF_SPACE not found")); + + int base = oldTypeOfSpace.getDisplayOrder(); + if (Boolean.TRUE.equals(oldTypeOfSpace.getIsActive())) { + svc.unlinkQuestion(oldTypeOfSpace.getQuestionId()); + } + + for (int i = 0; i < RELATIONSHIP_VALUES.size(); i++) { + String r = RELATIONSHIP_VALUES.get(i); + String typeOfSpaceUuid = "CCT_TYPE_OF_SPACE_" + r; + String areaUuid = "CCT_AREA_OF_SHARED_SPACE_" + r; + + // Type of Space for this relationship — revealed by CCT_RELATIONSHIP= + SectionQuestion typeOfSpace = svc.ensureQuestion(section, question(typeOfSpaceUuid, + "Type of Space", "स्थान का प्रकार", QuestionType.RADIO, null, base + 1 + 2 * i)); + svc.ensureValidation(typeOfSpace, validation(ValidationType.MANDATORY_IF, + "CCT_RELATIONSHIP=" + r, MANDATORY_ERROR)); + QuestionOption relationshipOption = svc.option(relationship, r) + .orElseThrow(() -> new IllegalStateException("Option CCT_RELATIONSHIP=" + r + " not found")); + svc.ensureCondition(relationshipOption, showQuestion(typeOfSpaceUuid), version); + + // Approximate Area of Shared Space for this relationship — revealed by any of its Type of Space options + SectionQuestion area = svc.ensureQuestion(section, question(areaUuid, + "Approximate Area of Shared Space", "साझा स्थान का अनुमानित क्षेत्रफल", QuestionType.NUMBER_PICKER, + "Give estimated measurement of area", base + 2 + 2 * i)); + svc.ensureValidation(area, validation(ValidationType.REGEX, AREA_REGEX, "Enter a value between 50 and 5000.")); + svc.ensureValidation(area, validation(ValidationType.UNIT, "sq. m.", "Value is in sq. m.")); + + for (int j = 0; j < TYPE_OF_SPACE_OPTIONS.size(); j++) { + String[] o = TYPE_OF_SPACE_OPTIONS.get(j); + QuestionOption spaceOption = svc.ensureOption(typeOfSpace, option(o[0], o[1], o[2], j + 1)); + svc.ensureValidation(area, validation(ValidationType.MANDATORY_IF, + typeOfSpaceUuid + "=" + o[2], MANDATORY_ERROR)); + svc.ensureCondition(spaceOption, showQuestion(areaUuid), version); + } + } + + } + + private SectionQuestionDTO question(String uuid, String text, String textHindi, QuestionType type, + String defaultValue, int order) { + SectionQuestionDTO q = new SectionQuestionDTO(); + q.setQuestionUuid(uuid); + q.setQuestionText(text); + q.setQuestionTextHindi(textHindi); + q.setQuestionType(type); + q.setDefaultValue(defaultValue); + q.setIsMandatory(true); + q.setDisplayOrder(order); + q.setVisibleByDefault(false); + q.setOptions(List.of()); + q.setValidations(List.of()); + return q; + } + + private QuestionOptionDTO option(String label, String labelHindi, String value, int order) { + QuestionOptionDTO o = new QuestionOptionDTO(); + o.setOptionLabel(label); + o.setOptionLabelHindi(labelHindi); + o.setOptionValue(value); + o.setOptionValueHindi(labelHindi); + o.setDisplayOrder(order); + o.setConditions(List.of()); + return o; + } + + private QuestionValidationDTO validation(ValidationType type, String param, String errorMessage) { + QuestionValidationDTO v = new QuestionValidationDTO(); + v.setValidationType(type); + v.setValidationParam(param); + v.setErrorMessage(errorMessage); + return v; + } + + private OptionConditionDTO showQuestion(String targetQuestionUuid) { + OptionConditionDTO c = new OptionConditionDTO(); + c.setActionType("SHOW_QUESTION"); + c.setTargetQuestionUuid(targetQuestionUuid); + return c; + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V007_AddRelationshipHoursQuestions.java b/src/main/java/com/iemr/flw/seeder/migration/V007_AddRelationshipHoursQuestions.java new file mode 100644 index 000000000..3486eea07 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V007_AddRelationshipHoursQuestions.java @@ -0,0 +1,129 @@ +/* + * 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.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.masterEnum.ValidationType; +import com.iemr.flw.service.DynamicFormReconciliationService; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Adds a mandatory "Time spent with contact in hours" number picker to the Community Contact + * Tracing form for each "Relationship with community contacts" (CCT_RELATIONSHIP) option, so the + * exposure duration is captured per relationship type alongside its existing contact count. + * + * One question per option (CCT_RELATIONSHIP_HOURS_<OPTION_VALUE>) rather than a shared one, + * since CCT_RELATIONSHIP is multi-select and a shared field couldn't disambiguate which duration + * belongs to which relationship. Each is hidden by default, revealed by a SHOW_QUESTION condition + * on its option, and mandatory only when that option is selected (MANDATORY_IF). + * + * Each question is inserted directly after its relationship's "Approximate Area of Shared Space" + * (CCT_AREA_OF_SHARED_SPACE_<OPTION_VALUE>), so every relationship's revealed questions read + * Type of Space, Area, Time spent; {@code ensureQuestion} shifts everything after it down by one. + * Must run after V006_PerRelationshipTypeOfSpace, which creates those Area questions — and since it + * runs later, each option's SHOW_QUESTION conditions are also created in that same order. + */ +@Component +public class V007_AddRelationshipHoursQuestions implements FormStructureMigration { + + private static final List RELATIONSHIP_VALUES = List.of( + "NEIGHBOUR", + "FRIEND", + "FELLOW_WORSHIPPER", + "FELLOW_COMMUTER", + "COMMUNITY_GROUP_MEMBER", + "FELLOW_PATIENT", + "OTHER"); + + private static final String QUESTION_TEXT = "Time spent with contact in hours"; + private static final String QUESTION_TEXT_HINDI = "संपर्क के साथ बिताया गया समय (घंटों में)"; + private static final String HOURS_REGEX = "^([0-9]|1[0-9]|2[0-4])$"; + private static final String HOURS_ERROR = "Enter whole hours between 0 and 24"; + + @Override + public String migrationId() { + return "V007"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + FormVersion version = svc.latestVersion("COMMUNITY_CONTACT_TRACING") + .orElseThrow(() -> new IllegalStateException( + "COMMUNITY_CONTACT_TRACING not found — must run after CommunityContactTracingFormSeeder")); + FormSection section = svc.section(version, "CCT_SEC_1") + .orElseThrow(() -> new IllegalStateException("Section CCT_SEC_1 not found")); + SectionQuestion relationship = svc.question(section, "CCT_RELATIONSHIP") + .orElseThrow(() -> new IllegalStateException("Question CCT_RELATIONSHIP not found")); + + for (String value : RELATIONSHIP_VALUES) { + String questionUuid = "CCT_RELATIONSHIP_HOURS_" + value; + String areaUuid = "CCT_AREA_OF_SHARED_SPACE_" + value; + + SectionQuestion area = svc.question(section, areaUuid) + .orElseThrow(() -> new IllegalStateException( + "Question " + areaUuid + " not found — must run after V006_PerRelationshipTypeOfSpace")); + SectionQuestion hours = svc.ensureQuestion(section, + hoursQuestion(questionUuid, area.getDisplayOrder() + 1)); + svc.ensureValidation(hours, validation(ValidationType.REGEX, HOURS_REGEX, HOURS_ERROR)); + svc.ensureValidation(hours, validation(ValidationType.MANDATORY_IF, + "CCT_RELATIONSHIP=" + value, "This field is mandatory")); + + QuestionOption option = svc.option(relationship, value) + .orElseThrow(() -> new IllegalStateException("Option CCT_RELATIONSHIP=" + value + " not found")); + OptionConditionDTO show = new OptionConditionDTO(); + show.setActionType("SHOW_QUESTION"); + show.setTargetQuestionUuid(questionUuid); + svc.ensureCondition(option, show, version); + } + } + + private SectionQuestionDTO hoursQuestion(String uuid, int order) { + SectionQuestionDTO q = new SectionQuestionDTO(); + q.setQuestionUuid(uuid); + q.setQuestionText(QUESTION_TEXT); + q.setQuestionTextHindi(QUESTION_TEXT_HINDI); + q.setQuestionType(QuestionType.NUMBER_PICKER); + q.setIsMandatory(true); + q.setDisplayOrder(order); + q.setVisibleByDefault(false); + q.setOptions(List.of()); + q.setValidations(List.of()); + return q; + } + + private QuestionValidationDTO validation(ValidationType type, String param, String errorMessage) { + QuestionValidationDTO v = new QuestionValidationDTO(); + v.setValidationType(type); + v.setValidationParam(param); + v.setErrorMessage(errorMessage); + return v; + } +} diff --git a/src/main/java/com/iemr/flw/seeder/migration/V008_ChangeRelationshipToDropdownMulti.java b/src/main/java/com/iemr/flw/seeder/migration/V008_ChangeRelationshipToDropdownMulti.java new file mode 100644 index 000000000..7db08a382 --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V008_ChangeRelationshipToDropdownMulti.java @@ -0,0 +1,77 @@ +/* + * 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.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.service.DynamicFormReconciliationService; +import org.springframework.stereotype.Component; + +/** + * Changes the Community Contact Tracing form's "Relationship with community contacts" question + * (CCT_RELATIONSHIP) from CHECKBOX_MULTI to DROPDOWN_MULTI, so the 7 relationship options render as + * a multi-select dropdown instead of a checkbox list. + * + * Both types submit {@code optionValues} and store one response row per selected option, so + * existing responses remain valid. Options and their conditions (per-relationship count, Type of + * Space and hours questions, and "Other" text) are untouched. All other scalar fields are read off + * the existing row and passed back unchanged, since {@code updateQuestion} overwrites all of them + * unconditionally. + */ +@Component +public class V008_ChangeRelationshipToDropdownMulti implements FormStructureMigration { + + @Override + public String migrationId() { + return "V008"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + FormVersion version = svc.latestVersion("COMMUNITY_CONTACT_TRACING") + .orElseThrow(() -> new IllegalStateException( + "COMMUNITY_CONTACT_TRACING not found — must run after CommunityContactTracingFormSeeder")); + FormSection section = svc.section(version, "CCT_SEC_1") + .orElseThrow(() -> new IllegalStateException("Section CCT_SEC_1 not found")); + SectionQuestion question = svc.question(section, "CCT_RELATIONSHIP") + .orElseThrow(() -> new IllegalStateException("Question CCT_RELATIONSHIP not found")); + + if (question.getQuestionType() == QuestionType.DROPDOWN_MULTI) { + return; + } + + SectionQuestionDTO dto = new SectionQuestionDTO(); + dto.setQuestionText(question.getQuestionText()); + dto.setQuestionTextHindi(question.getQuestionTextHindi()); + dto.setQuestionType(QuestionType.DROPDOWN_MULTI); + dto.setIsMandatory(question.getIsMandatory()); + dto.setMaxLength(question.getMaxLength()); + dto.setDefaultValue(question.getDefaultValue()); + dto.setContainsPii(question.getContainsPii()); + dto.setDisplayOrder(question.getDisplayOrder()); + + svc.updateQuestion(question.getQuestionId(), dto); + } +} 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 000000000..bfcb384d2 --- /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/BeneficiaryService.java b/src/main/java/com/iemr/flw/service/BeneficiaryService.java index e69bc887f..d043e7eea 100644 --- a/src/main/java/com/iemr/flw/service/BeneficiaryService.java +++ b/src/main/java/com/iemr/flw/service/BeneficiaryService.java @@ -5,11 +5,14 @@ import com.iemr.flw.dto.iemr.SAMResponseDTO; import java.util.List; +import java.util.Map; public interface BeneficiaryService { String getBenData(GetBenRequestHandler requestDTO, String authorisation) throws Exception; + Map getBeneficiaryRecordsByRegIds(List benRegIds, String authorisation); + String saveEyeCheckupVsit(List eyeCheckupRequestDTOS,String token); List getEyeCheckUpVisit(GetBenRequestHandler request,String token); diff --git a/src/main/java/com/iemr/flw/service/CampConfigService.java b/src/main/java/com/iemr/flw/service/CampConfigService.java index 305bf1f05..325b0dabf 100644 --- a/src/main/java/com/iemr/flw/service/CampConfigService.java +++ b/src/main/java/com/iemr/flw/service/CampConfigService.java @@ -1,8 +1,14 @@ package com.iemr.flw.service; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.util.List; + /** * Camp/van identity for this deployment. * @@ -17,12 +23,14 @@ * No inline default — every properties file must set stoptb.van.id explicitly, so a forgotten * config fails loudly at startup instead of silently running unconfigured. * - * Scope: vanID (and the VanSerialNo stamping that depends on it) only. parkingPlaceID is out of - * scope for this change. + * The van's parking place and store (facility) come from m_van, the same source MMU uses + * (MasterVanRepo.getFacilityID), and are read once and cached since the van never changes. */ @Service public class CampConfigService { + private final Logger logger = LoggerFactory.getLogger(CampConfigService.class); + @Value("${stoptb.van.id}") private int vanID; @@ -31,6 +39,12 @@ public class CampConfigService { @Value("${stoptb.enforce.vanid}") private boolean enforceVanID; + @PersistenceContext(unitName = "db_iemr") + private EntityManager entityManager; + + private volatile Integer parkingPlaceID; + private volatile Integer facilityID; + public Integer getVanID() { if (vanID <= 0) { if (enforceVanID) { @@ -42,13 +56,51 @@ public Integer getVanID() { return vanID; } + /** + * The configured van (stoptb.van.id) is always used. A vanID sent by the app is ignored, so data and + * stock never land on another camp's van/store; a different value is only logged. + */ + public Integer resolveVanID(Integer requestedVanID) { + Integer configured = getVanID(); + if (requestedVanID != null && requestedVanID > 0 && !requestedVanID.equals(configured)) { + logger.warn("Ignoring vanID " + requestedVanID + " from request; using stoptb.van.id " + configured); + } + return configured; + } + public boolean isCampConfigured() { return vanID > 0; } - // Not sourced from Redis anymore (out of scope for this change) — kept only because - // callers across StopTBServiceImpl/DiagnosticOrderServiceImpl/etc. still call it. + // Parking place of the configured van (m_van.ParkingPlaceID); 0 when the camp is not configured + // or the van is not found, which is what callers received before this lookup existed. public Integer getParkingPlaceID() { - return 0; + if (parkingPlaceID == null) loadVanDetails(); + return parkingPlaceID != null ? parkingPlaceID : 0; + } + + // Store mapped to the configured van (m_van.FacilityID); null when no store is mapped. + public Integer getFacilityID() { + if (facilityID == null) loadVanDetails(); + return facilityID; + } + + private synchronized void loadVanDetails() { + if (!isCampConfigured() || (parkingPlaceID != null && facilityID != null)) return; + try { + List rows = entityManager.createNativeQuery( + "SELECT ParkingPlaceID, FacilityID FROM db_iemr.m_van WHERE VanID = :vanID AND Deleted = false") + .setParameter("vanID", vanID) + .getResultList(); + if (rows.isEmpty()) { + logger.warn("stoptb.van.id " + vanID + " not found in m_van"); + return; + } + Object[] row = (Object[]) rows.get(0); + parkingPlaceID = row[0] != null ? ((Number) row[0]).intValue() : null; + facilityID = row[1] != null ? ((Number) row[1]).intValue() : null; + } catch (Exception e) { + logger.error("Cannot read m_van details for vanID " + vanID, e); + } } } diff --git a/src/main/java/com/iemr/flw/service/DiagnosticOrderService.java b/src/main/java/com/iemr/flw/service/DiagnosticOrderService.java index 0bd5207b8..42fb1c337 100644 --- a/src/main/java/com/iemr/flw/service/DiagnosticOrderService.java +++ b/src/main/java/com/iemr/flw/service/DiagnosticOrderService.java @@ -12,18 +12,50 @@ public interface DiagnosticOrderService { - DiagnosticOrder createAndPushOrder(DiagnosticOrderRequestDto request) throws Exception; + DiagnosticOrder createAndPushOrderByUser(DiagnosticOrderRequestDto request, String jwtToken) throws Exception; + + /** + * Same create/push logic as createAndPushOrder, attributed to "SYSTEM" instead of a JWT-derived + * user. For callers with no authenticated user in context, e.g. the poll scheduler auto-recreating + * an order after an invalid result. + */ + DiagnosticOrder createAndPushOrderAsSystem(DiagnosticOrderRequestDto request) throws Exception; DiagnosticOrderResultDto processResult(DiagnosticOrder order, DiagnosticPollResult result) throws Exception; + /** + * Polls the vendor once for this order. The order is re-read first and skipped (returns null) if it + * is no longer PENDING/IN_PROGRESS, e.g. a manual result landed after the scheduler loaded it. + */ DiagnosticPollResult pollOnce(DiagnosticOrder order) throws Exception; + /** + * Daily cutoff: marks this order CLOSED with the given reason and notifies the vendor, unless it was + * resolved (e.g. by a manual result) after the scheduler loaded it. + */ + void expireOrder(DiagnosticOrder order, String reason) throws Exception; + DiagnosticOrderResultDto triggerManualPoll(Long beneficiaryId, String orderType, Long visitCode) throws Exception; DiagnosticOrder retryPoll(Long beneficiaryId, String orderType, Long visitCode) throws Exception; + /** + * Best-effort: tells the vendor this order is closed out (no result coming), so they stop + * tracking it. Never throws — a provider failure is logged and swallowed, since the order's own + * CLOSED status is what actually matters locally. No-op if the order was never pushed to a vendor. + */ + void notifyProviderOrderClosed(DiagnosticOrder order, String reason); + DiagnosticOrderResultDto getOrderResult(Long beneficiaryId, String orderType, Long visitCode); + /** + * Orders with their result, keyed by order id (STOP-TB changes feed). Deleted orders are left + * out. Each record carries what getBeneficiariesByStatus and getOrderResult give today: the + * beneficiary, order type, visit code and status (the app buckets by the latest order per + * beneficiary and type), plus the result fields. + */ + java.util.Map> getOrderRecordsByIds(java.util.Collection ids); + DiagnosticOrder getOrder(Long beneficiaryId, String orderType, Long visitCode) throws Exception; List getOrdersByBeneficiaryId(Long beneficiaryId) throws Exception; @@ -32,5 +64,5 @@ public interface DiagnosticOrderService { VendorHealthDto checkVendorHealth(String orderType) throws Exception; - DiagnosticOrderResultDto submitManualResult(ManualDiagnosticResultRequestDto request) throws Exception; + DiagnosticOrderResultDto submitManualResult(ManualDiagnosticResultRequestDto request, String jwtToken) throws Exception; } diff --git a/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java b/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java index c7aae24df..b3e5558c9 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; @@ -47,7 +48,7 @@ public interface DynamicFormDefinitionService { /** Returns a specific version's full definition tree (no cache). */ DynamicFormDTO getFormDefinitionByVersion(Long formId, Integer versionNumber); - /** Returns metadata for all active forms (without full tree). */ + /** Returns every active form's latest full definition, with each version's full definition in {@code versions}. */ List getAllForms(); /** Sets the form's isActive flag to true. */ @@ -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/DynamicFormReconciliationService.java b/src/main/java/com/iemr/flw/service/DynamicFormReconciliationService.java new file mode 100644 index 000000000..f558f0078 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/DynamicFormReconciliationService.java @@ -0,0 +1,101 @@ +/* + * 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.service; + +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.domain.iemr.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.OptionCondition; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.QuestionValidation; +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.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; + +import java.util.Optional; + +/** + * Idempotent, in-place reconciliation for dynamic form structure — inserts whatever is missing + * from the current latest {@link FormVersion} and leaves existing rows untouched. Never creates a + * new version (unlike {@link DynamicFormDefinitionService#updateForm}, which always clones one). + * + * Used both by the startup seeders (walking their full hardcoded DTO tree every run) and by the + * granular structure endpoints (a single section/question/option at a time). + * + * Each {@code ensureX} method operates on exactly one level — callers walk the tree themselves and + * call the next level down, since only the caller knows whether it's safe yet to wire cross-sibling + * references (see {@link #ensureCondition}). + */ +public interface DynamicFormReconciliationService { + + /** Finds the form by formUuid, or creates it. If found inactive, reactivates it (touches no other field). */ + DynamicForm ensureForm(DynamicFormDTO dto); + + /** Finds the form's isLatest=true version, or creates version 1 if none exists yet. */ + FormVersion ensureLatestVersion(DynamicForm form); + + /** Finds a section by sectionUuid within the version, or creates it. */ + FormSection ensureSection(FormVersion version, FormSectionDTO dto); + + /** Finds a question by questionUuid within the section, or creates it (a section's question is "linked" the moment it's created — no separate link step exists). */ + SectionQuestion ensureQuestion(FormSection section, SectionQuestionDTO dto); + + /** Finds an option by optionValue within the question, or creates it. */ + QuestionOption ensureOption(SectionQuestion question, QuestionOptionDTO dto); + + /** Finds a validation by (validationType, validationParam) within the question, or creates it — validations carry no natural key of their own. */ + QuestionValidation ensureValidation(SectionQuestion question, QuestionValidationDTO dto); + + /** + * Finds a condition by (actionType, target) within the option, or creates it, resolving + * targetQuestionUuid/targetSectionUuid against the given version. Call only once every sibling + * section/question this condition might target already exists as a row. + */ + OptionCondition ensureCondition(QuestionOption option, OptionConditionDTO dto, FormVersion version); + + /** Updates a question's scalar fields only (options/validations are managed by their own endpoints). A displayOrder change moves the question among its siblings, shifting them accordingly. */ + SectionQuestion updateQuestion(Long questionId, SectionQuestionDTO dto); + + /** Soft-deletes (isActive=false) a question — never hard-deleted; historical responses may reference it. */ + void unlinkQuestion(Long questionId); + + /** Soft-deletes (isActive=false) an option — never hard-deleted; historical responses may reference it. */ + void removeOption(Long optionId); + + // ── Read-only lookups, for FormStructureMigration classes to locate what they're changing ── + + /** Finds the given form's current latest version, if the form exists at all. */ + Optional latestVersion(String formUuid); + + /** Finds a section by sectionUuid within the given version. */ + Optional section(FormVersion version, String sectionUuid); + + /** Finds a question by questionUuid within the given section. */ + Optional question(FormSection section, String questionUuid); + + /** Finds an option by optionValue within the given question. */ + Optional option(SectionQuestion question, String optionValue); +} diff --git a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java index 1f2255f3e..8265cfafb 100644 --- a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java +++ b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java @@ -55,6 +55,12 @@ List getResponsesByBeneficiary(Long beneficiaryId, Integer vill /** Single response with all nested section and question answers. */ FormResponseDTO getResponseById(Long responseId); + /** + * Responses with all nested answers, keyed by responseId, as getResponsesByBeneficiary returns + * them (STOP-TB changes feed). Ids with no response are left out. + */ + java.util.Map getResponsesByIds(java.util.Collection responseIds); + /** * Submit multiple form responses in one bulk transaction. * All FormResponse rows are batch-inserted via saveAll() so responseIds are available diff --git a/src/main/java/com/iemr/flw/service/StopTBPrescriptionService.java b/src/main/java/com/iemr/flw/service/StopTBPrescriptionService.java new file mode 100644 index 000000000..c61b4d4f9 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/StopTBPrescriptionService.java @@ -0,0 +1,721 @@ +package com.iemr.flw.service; + +import com.iemr.flw.domain.identity.RMNCHMBeneficiarydetail; +import com.iemr.flw.domain.identity.RMNCHMBeneficiarymapping; +import com.iemr.flw.domain.iemr.BenVisitDetail; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.Period; +import java.util.*; + +/** + * Stop TB nurse OPD: chief complaints, prescription and dispensing written to the same standard + * tables MMU/TM and Inventory-API use, inside the caller's transaction. + * + * - Chief complaints -> t_benchiefcomplaint (one row per complaint, like TM saveBenChiefComplaints) + * - Prescription -> t_prescription + t_prescribeddrug (DrugID + QtyPrescribed, like TM doctor save) + * - Dispensing -> t_patientissue + t_itemstockexit (ExitType T_PatientIssue) and + * t_itemstockentry.QuantityInHand reduced, like Inventory-API issuePatientDrugs. + * + * Batches are picked by m_itemcategory.IssueType (FEFO / FIFO / LIFO) from non-expired batches that + * last the treatment duration, and are locked (SELECT ... FOR UPDATE) so two nurses can never take the + * same stock. If any drug is short, nothing is saved (InsufficientStockException rolls back the caller). + * + * Native SQL only, no new entity mappings: FLW runs with ddl-auto=create. + */ +@Service +public class StopTBPrescriptionService { + + private static final String REFERENCE_PREFIX = "StopTB:"; + + @PersistenceContext(unitName = "db_iemr") + private EntityManager em; + + @Autowired + private CampConfigService campConfigService; + + @Autowired + private BeneficiaryRepo beneficiaryRepo; + + // Off by default: save the prescription only (no store/stock check, no patient issue, stock unchanged). + // true = check stock and dispense from the camp store. + @Value("${stoptb.dispense.enabled:false}") + private boolean dispenseEnabled; + + private final Logger logger = LoggerFactory.getLogger(StopTBPrescriptionService.class); + + public static class InsufficientStockException extends RuntimeException { + public InsufficientStockException(String message) { + super(message); + } + } + + /** Previous result for a submissionId already saved, or null. Lets the app retry safely. */ + @Transactional(propagation = Propagation.MANDATORY) + public Map findPreviousSubmission(Long beneficiaryRegID, String submissionId) { + if (submissionId == null || submissionId.isBlank()) return null; + List rows = em.createNativeQuery("SELECT PatientIssueID, VisitCode, PrescriptionID FROM db_iemr.t_patientissue " + + "WHERE BeneficiaryRegID = :ben AND Reference = :ref AND Deleted = false") + .setParameter("ben", beneficiaryRegID) + .setParameter("ref", REFERENCE_PREFIX + submissionId) + .getResultList(); + if (rows.isEmpty()) return null; + Object[] row = (Object[]) rows.get(0); + Integer facilityID = campConfigService.getFacilityID(); + + List issued = em.createNativeQuery("SELECT e.ItemID, i.ItemName, SUM(x.Quantity) " + + "FROM db_iemr.t_itemstockexit x " + + "JOIN db_iemr.t_itemstockentry e ON e.VanSerialNo = x.ItemStockEntryID AND e.FacilityID = x.FacilityID " + + "JOIN db_iemr.m_item i ON i.ItemID = e.ItemID " + + "WHERE x.ExitType = 'T_PatientIssue' AND x.ExitTypeID = :issueID AND x.FacilityID = :facilityID " + + "GROUP BY e.ItemID, i.ItemName") + .setParameter("issueID", ((Number) row[0]).longValue()) + .setParameter("facilityID", facilityID) + .getResultList(); + List> dispensed = new ArrayList<>(); + for (Object o : issued) { + Object[] r = (Object[]) o; + int drugID = ((Number) r[0]).intValue(); + Map d = new LinkedHashMap<>(); + d.put("drugID", drugID); + d.put("drugName", r[1]); + d.put("qtyIssued", ((Number) r[2]).intValue()); + d.put("availableQuantity", availableQuantity(facilityID, drugID, 0)); + dispensed.add(d); + } + Map result = new LinkedHashMap<>(); + result.put("beneficiaryRegID", beneficiaryRegID); + result.put("visitCode", row[1] != null ? ((Number) row[1]).longValue() : null); + result.put("prescriptionID", row[2] != null ? ((Number) row[2]).longValue() : null); + result.put("dispensed", dispensed); + result.put("duplicate", true); + return result; + } + + /** + * Replaces the visit's chief complaints with the given list (edit = remove old + insert new, as MMU + * does on update). Rows without an ID and without a name are skipped. + */ + @Transactional(propagation = Propagation.MANDATORY) + public void saveChiefComplaints(List> complaints, Long beneficiaryRegID, BenVisitDetail visit, + String createdBy, Integer vanID, Integer parkingPlaceID) { + if (complaints == null) return; + // Processed='N' so the removal is uploaded to central again (central updates rows it already has). + em.createNativeQuery("UPDATE db_iemr.t_benchiefcomplaint SET Deleted = true, Processed = 'N', ModifiedBy = :user " + + "WHERE BeneficiaryRegID = :ben AND VisitCode = :visitCode AND Deleted = false") + .setParameter("user", createdBy) + .setParameter("ben", beneficiaryRegID) + .setParameter("visitCode", visit.getVisitCode()) + .executeUpdate(); + for (Map c : complaints) { + Integer complaintID = toInt(c.get("chiefComplaintID")); + String complaint = toStr(c.get("chiefComplaint")); + // ID from the chief complaint master is required: getAll and reports identify new records by it. + if (complaintID == null) { + throw new IllegalArgumentException("chiefComplaintID is required for every chief complaint" + + (complaint != null ? " (" + complaint + ")" : "")); + } + em.createNativeQuery("INSERT INTO db_iemr.t_benchiefcomplaint (BeneficiaryRegID, BenVisitID, ProviderServiceMapID, " + + "VisitCode, ChiefComplaintID, ChiefComplaint, Duration, UnitOfDuration, Description, Deleted, " + + "Processed, CreatedBy, VanID, ParkingPlaceID) VALUES (:ben, :visitID, :psm, :visitCode, :cid, " + + ":name, :duration, :unit, :description, false, 'N', :user, :van, :pp)") + .setParameter("ben", beneficiaryRegID) + .setParameter("visitID", visit.getBenVisitId()) + .setParameter("psm", visit.getProviderServiceMapID()) + .setParameter("visitCode", visit.getVisitCode()) + .setParameter("cid", complaintID) + .setParameter("name", complaint) + .setParameter("duration", toInt(c.get("duration"))) + .setParameter("unit", toStr(c.get("unitOfDuration"))) + .setParameter("description", toStr(c.get("description"))) + .setParameter("user", createdBy) + .setParameter("van", vanID) + .setParameter("pp", parkingPlaceID) + .executeUpdate(); + stampVanSerialNo("t_benchiefcomplaint", "ID", lastInsertId()); + } + } + + /** + * Saves the prescription and issues every drug from the camp store. Returns prescriptionID and, + * per drug, the quantity issued and what is left in the store. + */ + @Transactional(propagation = Propagation.MANDATORY) + public Map prescribeAndDispense(Map prescription, Long beneficiaryRegID, + BenVisitDetail visit, String submissionId, String createdBy, Integer vanID, Integer parkingPlaceID) { + List> drugs = toList(prescription.get("drugs")); + if (!dispenseEnabled) { + return prescribeWithoutDispensing(prescription, drugs, beneficiaryRegID, visit, createdBy, vanID, + parkingPlaceID); + } + Map result = new LinkedHashMap<>(); + if (drugs.isEmpty()) { + // Remarks without medicine are still kept, as MMU saves the visit instruction without drugs. + String instruction = toStr(prescription.get("instruction")); + if (instruction != null && !instruction.isBlank()) { + result.put("prescriptionID", insertPrescription(beneficiaryRegID, visit, instruction, createdBy, vanID, + parkingPlaceID)); + } + return result; + } + + Integer facilityID = campConfigService.getFacilityID(); + if (facilityID == null) { + throw new IllegalStateException("No store is mapped to van " + vanID + " (m_van.FacilityID)"); + } + + // 1. Validate every line and check total stock per drug before writing anything. + Map requested = new LinkedHashMap<>(); + Map items = new HashMap<>(); + for (Map d : drugs) { + Integer drugID = toInt(d.get("drugID")); + if (drugID == null) throw new IllegalArgumentException("drugID is required for every drug"); + if (!items.containsKey(drugID)) items.put(drugID, getStoreItem(facilityID, drugID)); + Integer qty = toInt(d.get("qtyPrescribed")); + if (qty == null || qty <= 0) { + // No quantity from the app: tablets/capsules = doses per day x days, other forms = 1. + qty = calculateQuantity(d, toInt(items.get(drugID)[7])); + if (qty == null) { + throw new IllegalArgumentException("qtyPrescribed is required for drugID " + drugID + + " (tablet/capsule quantity needs frequency and duration)"); + } + d.put("qtyPrescribed", qty); // saved in t_prescribeddrug.QtyPrescribed + } + requested.merge(drugID, qty, Integer::sum); + } + List shortages = new ArrayList<>(); + Map> lockedBatches = new HashMap<>(); + for (Map.Entry r : requested.entrySet()) { + Object[] item = items.get(r.getKey()); + int durationDays = maxDurationDays(drugs, r.getKey()); + List batches = lockBatches(facilityID, r.getKey(), (String) item[6], durationDays); + lockedBatches.put(r.getKey(), batches); + int available = batches.stream().mapToInt(b -> ((Number) b[1]).intValue()).sum(); + if (available < r.getValue()) { + shortages.add(item[1] + " (drugID " + r.getKey() + "): asked " + r.getValue() + ", available " + available); + } + } + if (!shortages.isEmpty()) { + throw new InsufficientStockException("Insufficient stock - " + String.join("; ", shortages)); + } + + // 2. Prescription + prescribed drugs (Stop TB service line, same as the visit). + Integer storePsm = getStorePsm(facilityID); + long prescriptionID = insertPrescription(beneficiaryRegID, visit, toStr(prescription.get("instruction")), + createdBy, vanID, parkingPlaceID); + + for (Map d : drugs) { + Integer drugID = toInt(d.get("drugID")); + Object[] item = items.get(drugID); + em.createNativeQuery("INSERT INTO db_iemr.t_prescribeddrug (BeneficiaryRegID, BenVisitID, ProviderServiceMapID, " + + "VisitCode, PrescriptionID, DrugForm, DrugID, GenericDrugName, DrugStrength, Dose, Route, Frequency, " + + "Duration, DuartionUnit, SpecialInstruction, QtyPrescribed, isEDL, Deleted, Processed, CreatedBy, " + + "VanID, ParkingPlaceID) VALUES (:ben, :visitID, :psm, :visitCode, :prescriptionID, :form, :drugID, " + + ":name, :strength, :dose, :route, :frequency, :duration, :durationUnit, :instruction, :qty, " + + ":isEDL, false, 'N', :user, :van, :pp)") + .setParameter("ben", beneficiaryRegID) + .setParameter("visitID", visit.getBenVisitId()) + .setParameter("psm", visit.getProviderServiceMapID()) + .setParameter("visitCode", visit.getVisitCode()) + .setParameter("prescriptionID", prescriptionID) + .setParameter("form", item[3]) + .setParameter("drugID", drugID) + .setParameter("name", item[1]) + .setParameter("strength", item[2]) + .setParameter("dose", toStr(d.get("dose"))) + .setParameter("route", item[4]) + .setParameter("frequency", toStr(d.get("frequency"))) + .setParameter("duration", toStr(d.get("duration"))) + .setParameter("durationUnit", toStr(d.get("durationUnit"))) + .setParameter("instruction", toStr(d.get("instructions"))) + .setParameter("qty", toInt(d.get("qtyPrescribed"))) + .setParameter("isEDL", item[5]) + .setParameter("user", createdBy) + .setParameter("van", vanID) + .setParameter("pp", parkingPlaceID) + .executeUpdate(); + stampVanSerialNo("t_prescribeddrug", "PrescribedDrugID", lastInsertId()); + } + + // 3. Patient issue header (same shape as Inventory-API issuePatientDrugs, IssueType 'System'). + Object[] patient = getPatientDetails(beneficiaryRegID); + em.createNativeQuery("INSERT INTO db_iemr.t_patientissue (BeneficiaryRegID, BenVisitID, VisitCode, FacilityID, " + + "PatientName, Age, Gender, PrescriptionID, Reference, IssueType, IssuedBy, ProviderServiceMapID, " + + "Deleted, Processed, CreatedBy, SyncFacilityID, VanID, ParkingPlaceID) VALUES (:ben, :visitID, " + + ":visitCode, :facilityID, :name, :age, :gender, :prescriptionID, :ref, 'System', :user, :psm, false, " + + "'N', :user, :facilityID, :van, :pp)") + .setParameter("ben", beneficiaryRegID) + .setParameter("name", patient[0]) + .setParameter("age", patient[1]) + .setParameter("gender", patient[2]) + .setParameter("visitID", visit.getBenVisitId()) + .setParameter("visitCode", visit.getVisitCode()) + .setParameter("facilityID", facilityID) + .setParameter("prescriptionID", prescriptionID) + .setParameter("ref", submissionId != null && !submissionId.isBlank() ? REFERENCE_PREFIX + submissionId : null) + .setParameter("user", createdBy) + .setParameter("psm", storePsm) + .setParameter("van", vanID) + .setParameter("pp", parkingPlaceID) + .executeUpdate(); + long patientIssueID = lastInsertId(); + stampVanSerialNo("t_patientissue", "PatientIssueID", patientIssueID); + + // 4. Take each drug from its locked batches in issue order; one stock exit per batch used. + List> dispensed = new ArrayList<>(); + for (Map.Entry r : requested.entrySet()) { + int remaining = r.getValue(); + for (Object[] batch : lockedBatches.get(r.getKey())) { + if (remaining == 0) break; + long batchSerialNo = ((Number) batch[0]).longValue(); + int take = Math.min(remaining, ((Number) batch[1]).intValue()); + em.createNativeQuery("INSERT INTO db_iemr.t_itemstockexit (ItemStockEntryID, FacilityID, Quantity, " + + "ProviderServiceMapID, ExitTypeID, ExitType, Deleted, Processed, CreatedBy, SyncFacilityID, " + + "VanID, ParkingPlaceID) VALUES (:batch, :facilityID, :qty, :psm, :issueID, 'T_PatientIssue', " + + "false, 'N', :user, :facilityID, :van, :pp)") + .setParameter("batch", batchSerialNo) + .setParameter("facilityID", facilityID) + .setParameter("qty", take) + .setParameter("psm", storePsm) + .setParameter("issueID", patientIssueID) + .setParameter("user", createdBy) + .setParameter("van", vanID) + .setParameter("pp", parkingPlaceID) + .executeUpdate(); + stampVanSerialNo("t_itemstockexit", "ItemStockExitID", lastInsertId()); + // Same update as Inventory-API ItemStockEntryRepo.updateStock. Processed='N' sends the batch's + // new stock to central on the next upload; central updates its copy by VanSerialNo + store. + em.createNativeQuery("UPDATE db_iemr.t_itemstockentry SET QuantityInHand = QuantityInHand - :qty, " + + "Processed = 'N' WHERE VanSerialNo = :batch AND FacilityID = :facilityID") + .setParameter("qty", take) + .setParameter("batch", batchSerialNo) + .setParameter("facilityID", facilityID) + .executeUpdate(); + remaining -= take; + } + Map d = new LinkedHashMap<>(); + d.put("drugID", r.getKey()); + d.put("drugName", items.get(r.getKey())[1]); + d.put("qtyIssued", r.getValue()); + d.put("availableQuantity", availableQuantity(facilityID, r.getKey(), 0)); + dispensed.add(d); + } + + result.put("prescriptionID", prescriptionID); + result.put("dispensed", dispensed); + return result; + } + + /** + * OPD records for getAll from the standard tables, one per visit that was saved with the new payload + * (complaint with ChiefComplaintID or drug with DrugID). Older visits have only the free-text copy in + * tb_stoptb_general_opd and are added by the caller. Field names and formats match that table's response: + * chiefComplaint = JSON list of names, medication/dosage/frequency/duration = comma separated. + */ + @SuppressWarnings("unchecked") + public List> getStandardOpdRecords(Integer providerServiceMapID, Integer villageID) { + String villageFilter = villageID != null + ? "AND v.BeneficiaryRegID IN (SELECT f.beneficiary_reg_id FROM db_iemr.i_ben_flow_outreach f " + + "WHERE f.providerServiceMapID = :psm AND f.villageID = :villageID) " + : ""; + Map params = new HashMap<>(); + params.put("psm", providerServiceMapID); + if (villageID != null) params.put("villageID", villageID); + return standardOpdRecords("v.ProviderServiceMapID = :psm " + villageFilter, params); + } + + // The same records for specific visits (BenVisitID), for the STOP-TB changes feed. A visit that is + // deleted or has no complaint or drug is left out, exactly as getStandardOpdRecords leaves it out. + public List> getStandardOpdRecordsByVisitIds(Collection benVisitIds) { + if (benVisitIds.isEmpty()) return new ArrayList<>(); + Map params = new HashMap<>(); + params.put("ids", benVisitIds); + return standardOpdRecords("v.BenVisitID IN (:ids) ", params); + } + + // Visit codes among these that getStandardOpdRecords would return (not deleted, with a complaint or drug). + public Set visitCodesWithStandardOpd(Collection visitCodes) { + Set out = new HashSet<>(); + if (visitCodes.isEmpty()) return out; + Map params = new HashMap<>(); + params.put("codes", visitCodes); + for (Map m : standardOpdRecords("v.VisitCode IN (:codes) ", params)) { + out.add((Long) m.get("visitCode")); + } + return out; + } + + private List> standardOpdRecords(String visitFilter, Map params) { + Query visitQuery = em.createNativeQuery("SELECT v.BenVisitID, v.BeneficiaryRegID, v.VisitCode, v.CreatedBy, " + + "v.CreatedDate, v.LastModDate, v.ProviderServiceMapID FROM db_iemr.t_benvisitdetail v " + + "WHERE " + visitFilter + "AND v.Deleted = false " + + "AND (EXISTS (SELECT 1 FROM db_iemr.t_benchiefcomplaint c WHERE c.BeneficiaryRegID = v.BeneficiaryRegID " + + " AND c.VisitCode = v.VisitCode AND c.ChiefComplaintID IS NOT NULL AND c.Deleted = false) " + + " OR EXISTS (SELECT 1 FROM db_iemr.t_prescribeddrug d WHERE d.BeneficiaryRegID = v.BeneficiaryRegID " + + " AND d.VisitCode = v.VisitCode AND d.DrugID IS NOT NULL AND d.Deleted = false)) " + + "ORDER BY v.CreatedDate DESC"); + params.forEach(visitQuery::setParameter); + List visits = visitQuery.getResultList(); + + Map> byVisit = new LinkedHashMap<>(); + for (Object[] v : visits) { + Map m = new LinkedHashMap<>(); + m.put("id", ((Number) v[0]).longValue()); + m.put("beneficiaryRegID", ((Number) v[1]).longValue()); + m.put("visitCode", ((Number) v[2]).longValue()); + m.put("providerServiceMapID", v[6] != null ? ((Number) v[6]).intValue() : null); + m.put("chiefComplaint", new ArrayList()); + m.put("medication", new StringJoiner(", ")); + m.put("dosage", new StringJoiner(", ")); + m.put("frequency", new StringJoiner(", ")); + m.put("duration", new StringJoiner(", ")); + m.put("drugs", new ArrayList>()); + m.put("notes", null); + m.put("createdBy", v[3]); + m.put("createdDate", v[4]); + m.put("updateDate", v[5]); + m.put("updatedBy", null); + byVisit.put(((Number) v[2]).longValue(), m); + } + if (byVisit.isEmpty()) return new ArrayList<>(); + + List visitCodes = new ArrayList<>(byVisit.keySet()); + for (int i = 0; i < visitCodes.size(); i += 500) { + List chunk = visitCodes.subList(i, Math.min(i + 500, visitCodes.size())); + + for (Object o : em.createNativeQuery("SELECT VisitCode, ChiefComplaint, LastModDate FROM db_iemr.t_benchiefcomplaint " + + "WHERE VisitCode IN (:codes) AND ChiefComplaintID IS NOT NULL AND Deleted = false ORDER BY ID") + .setParameter("codes", chunk).getResultList()) { + Object[] r = (Object[]) o; + Map m = byVisit.get(((Number) r[0]).longValue()); + if (r[1] != null) ((List) m.get("chiefComplaint")).add(r[1].toString()); + latest(m, r[2]); + } + + for (Object o : em.createNativeQuery("SELECT d.VisitCode, d.GenericDrugName, d.Dose, d.Frequency, d.Duration, " + + "d.DuartionUnit, d.LastModDate, d.DrugID, i.ItemFormID, d.DrugForm, d.QtyPrescribed, " + + "d.SpecialInstruction FROM db_iemr.t_prescribeddrug d " + + "LEFT JOIN db_iemr.m_item i ON i.ItemID = d.DrugID " + + "WHERE d.VisitCode IN (:codes) AND d.DrugID IS NOT NULL AND d.Deleted = false " + + "ORDER BY d.PrescribedDrugID") + .setParameter("codes", chunk).getResultList()) { + Object[] r = (Object[]) o; + Map m = byVisit.get(((Number) r[0]).longValue()); + ((StringJoiner) m.get("medication")).add(r[1] != null ? r[1].toString() : ""); + ((StringJoiner) m.get("dosage")).add(r[2] != null ? r[2].toString() : ""); + ((StringJoiner) m.get("frequency")).add(r[3] != null ? r[3].toString() : ""); + ((StringJoiner) m.get("duration")).add(r[4] == null ? "" : r[5] == null ? r[4].toString() : r[4] + " " + r[5]); + latest(m, r[6]); + + // Full prescription per drug, so a saved record can show form, quantity and instructions. + Map drug = new LinkedHashMap<>(); + drug.put("drugID", ((Number) r[7]).intValue()); + drug.put("drugName", r[1]); + drug.put("itemFormID", r[8] != null ? ((Number) r[8]).intValue() : null); + drug.put("drugForm", r[9]); + drug.put("dose", r[2]); + drug.put("frequency", r[3]); + drug.put("duration", r[4] != null ? toInt(r[4]) : null); + drug.put("durationUnit", r[5]); + drug.put("qtyPrescribed", r[10] != null ? ((Number) r[10]).intValue() : null); + drug.put("instructions", r[11]); + ((List>) m.get("drugs")).add(drug); + } + + // Latest prescription instruction per visit is the visit's note. + for (Object o : em.createNativeQuery("SELECT VisitCode, Instruction, LastModDate FROM db_iemr.t_prescription " + + "WHERE VisitCode IN (:codes) AND Deleted = false ORDER BY PrescriptionID") + .setParameter("codes", chunk).getResultList()) { + Object[] r = (Object[]) o; + Map m = byVisit.get(((Number) r[0]).longValue()); + if (r[1] != null && !r[1].toString().isBlank()) m.put("notes", r[1].toString()); + latest(m, r[2]); + } + } + + com.google.gson.Gson gson = new com.google.gson.Gson(); + List> records = new ArrayList<>(); + for (Map m : byVisit.values()) { + List complaints = (List) m.get("chiefComplaint"); + m.put("chiefComplaint", complaints.isEmpty() ? null : gson.toJson(complaints)); + for (String key : new String[] { "medication", "dosage", "frequency", "duration" }) { + String joined = m.get(key).toString(); + m.put(key, joined.replace(",", "").isBlank() ? null : joined); + } + records.add(m); + } + return records; + } + + // updateDate = latest change on the visit, so the app picks up a later save on the same day. + private void latest(Map m, Object modDate) { + if (modDate instanceof Date && (m.get("updateDate") == null || ((Date) modDate).after((Date) m.get("updateDate")))) { + m.put("updateDate", modDate); + } + } + + // Name, age (years), gender for the issue row shown on the Inventory dispense screen. Missing details + // never block dispensing, same as Inventory-API. + private Object[] getPatientDetails(Long beneficiaryRegID) { + try { + RMNCHMBeneficiarymapping mapping = beneficiaryRepo.getById(BigInteger.valueOf(beneficiaryRegID)); + RMNCHMBeneficiarydetail detail = (mapping != null && mapping.getBenDetailsId() != null) + ? beneficiaryRepo.getDetailsById(mapping.getBenDetailsId()) + : null; + if (detail == null) return new Object[3]; + StringJoiner name = new StringJoiner(" "); + for (String part : new String[] { detail.getFirstName(), detail.getMiddleName(), detail.getLastName() }) { + if (part != null && !part.isBlank()) name.add(part.trim()); + } + Integer age = detail.getDob() != null + ? Period.between(detail.getDob().toLocalDateTime().toLocalDate(), LocalDate.now()).getYears() + : null; + String fullName = name.length() > 150 ? name.toString().substring(0, 150) : name.toString(); + return new Object[] { fullName.isEmpty() ? null : fullName, age, detail.getGender() }; + } catch (Exception e) { + logger.warn("Cannot read patient details for benRegID " + beneficiaryRegID + ": " + e.getMessage()); + return new Object[3]; + } + } + + /** + * Dispensing off (stoptb.dispense.enabled=false): the prescription is saved as the app sent it. No store or + * stock check and no patient issue, so drugs from the app's own list need not exist in this camp's store; + * DrugID, name and form are taken from the request. A new save replaces the visit's earlier prescription + * (same as chief complaints), so an edit or retry does not leave a second copy. + */ + private Map prescribeWithoutDispensing(Map prescription, + List> drugs, Long beneficiaryRegID, BenVisitDetail visit, String createdBy, + Integer vanID, Integer parkingPlaceID) { + for (Map d : drugs) { + if (toInt(d.get("drugID")) == null) throw new IllegalArgumentException("drugID is required for every drug"); + } + // Processed='N' so the removal is uploaded to central again (central updates rows it already has). + for (String table : new String[] { "t_prescribeddrug", "t_prescription" }) { + em.createNativeQuery("UPDATE db_iemr." + table + " SET Deleted = true, Processed = 'N', ModifiedBy = :user " + + "WHERE BeneficiaryRegID = :ben AND VisitCode = :visitCode AND Deleted = false") + .setParameter("user", createdBy) + .setParameter("ben", beneficiaryRegID) + .setParameter("visitCode", visit.getVisitCode()) + .executeUpdate(); + } + + Map result = new LinkedHashMap<>(); + String instruction = toStr(prescription.get("instruction")); + if (!drugs.isEmpty() || (instruction != null && !instruction.isBlank())) { + long prescriptionID = insertPrescription(beneficiaryRegID, visit, instruction, createdBy, vanID, + parkingPlaceID); + for (Map d : drugs) { + Integer qty = toInt(d.get("qtyPrescribed")); + if (qty == null || qty <= 0) qty = calculateQuantity(d, toInt(d.get("itemFormID"))); // null if unknown + em.createNativeQuery("INSERT INTO db_iemr.t_prescribeddrug (BeneficiaryRegID, BenVisitID, " + + "ProviderServiceMapID, VisitCode, PrescriptionID, DrugForm, DrugID, GenericDrugName, Dose, " + + "Frequency, Duration, DuartionUnit, SpecialInstruction, QtyPrescribed, Deleted, Processed, " + + "CreatedBy, VanID, ParkingPlaceID) VALUES (:ben, :visitID, :psm, :visitCode, " + + ":prescriptionID, :form, :drugID, :name, :dose, :frequency, :duration, :durationUnit, " + + ":instruction, :qty, false, 'N', :user, :van, :pp)") + .setParameter("ben", beneficiaryRegID) + .setParameter("visitID", visit.getBenVisitId()) + .setParameter("psm", visit.getProviderServiceMapID()) + .setParameter("visitCode", visit.getVisitCode()) + .setParameter("prescriptionID", prescriptionID) + .setParameter("form", toStr(d.get("drugForm"))) + .setParameter("drugID", toInt(d.get("drugID"))) + .setParameter("name", toStr(d.get("drugName"))) + .setParameter("dose", toStr(d.get("dose"))) + .setParameter("frequency", toStr(d.get("frequency"))) + .setParameter("duration", toStr(d.get("duration"))) + .setParameter("durationUnit", toStr(d.get("durationUnit"))) + .setParameter("instruction", toStr(d.get("instructions"))) + .setParameter("qty", qty) + .setParameter("user", createdBy) + .setParameter("van", vanID) + .setParameter("pp", parkingPlaceID) + .executeUpdate(); + stampVanSerialNo("t_prescribeddrug", "PrescribedDrugID", lastInsertId()); + } + result.put("prescriptionID", prescriptionID); + } + result.put("dispensed", new ArrayList>()); + return result; + } + + // t_prescription row for the visit (Stop TB service line, same as the visit). + private long insertPrescription(Long beneficiaryRegID, BenVisitDetail visit, String instruction, String createdBy, + Integer vanID, Integer parkingPlaceID) { + em.createNativeQuery("INSERT INTO db_iemr.t_prescription (BeneficiaryRegID, BenVisitID, ProviderServiceMapID, VisitCode, " + + "Instruction, Deleted, Processed, CreatedBy, VanID, ParkingPlaceID) " + + "VALUES (:ben, :visitID, :psm, :visitCode, :instruction, false, 'N', :user, :van, :pp)") + .setParameter("ben", beneficiaryRegID) + .setParameter("visitID", visit.getBenVisitId()) + .setParameter("psm", visit.getProviderServiceMapID()) + .setParameter("visitCode", visit.getVisitCode()) + .setParameter("instruction", instruction) + .setParameter("user", createdBy) + .setParameter("van", vanID) + .setParameter("pp", parkingPlaceID) + .executeUpdate(); + long prescriptionID = lastInsertId(); + stampVanSerialNo("t_prescription", "PrescriptionID", prescriptionID); + return prescriptionID; + } + + /** + * Units to give when the app sends no quantity – MMU's rule (CommonNurseServiceImpl.calculateQtyPrescribed). + * Tablets/capsules: tablets per intake x intakes per day x days, rounded up. Tablets per intake come from the + * dose (Half Tab 0.5, One Tab 1, One & Half Tab 1.5, Two Tabs 2); no dose sent = one tablet (capsule always 1). + * Single/Stat dose = one intake. SOS = up to one intake a day (one intake when no duration). Once in a week = + * one intake per 7 days. Other forms (syrup, cream, injection, drops...): 1 bottle/tube/vial. Null when a + * tablet/capsule quantity cannot be worked out (unknown frequency or missing duration). + */ + private Integer calculateQuantity(Map drug, Integer formID) { + if (formID == null || (formID != 1 && formID != 2)) return 1; // 1 = Tablet, 2 = Capsule + double perIntake = formID == 2 ? 1 : tabletsPerIntake(toStr(drug.get("dose"))); + String frequency = Optional.ofNullable(toStr(drug.get("frequency"))).orElse("").toUpperCase(); + if (frequency.contains("SINGLE DOSE") || frequency.contains("STAT")) return (int) Math.ceil(perIntake); + + Integer duration = toInt(drug.get("duration")); + boolean sos = frequency.contains("SOS"); + if (duration == null || duration <= 0) return sos ? (int) Math.ceil(perIntake) : null; + String unit = Optional.ofNullable(toStr(drug.get("durationUnit"))).orElse("Day").toLowerCase(); + int days = unit.startsWith("week") ? duration * 7 : unit.startsWith("month") ? duration * 30 + : unit.startsWith("year") ? duration * 365 : duration; + + if (frequency.contains("WEEK")) return (int) Math.ceil(perIntake * ((days + 6) / 7)); // Once in a Week + int perDay; + if (frequency.contains("QID") || frequency.contains("FOUR")) perDay = 4; + else if (frequency.contains("TID") || frequency.contains("THRICE")) perDay = 3; + else if (frequency.contains("BD") || frequency.contains("TWICE")) perDay = 2; + else if (frequency.contains("OD") || frequency.contains("ONCE DAILY") || sos) perDay = 1; // SOS: up to 1 a day + else return null; // unknown frequency + return (int) Math.ceil(perIntake * perDay * days); + } + + // MMU dose names (m_drugdose); anything else or no dose = one tablet + private static double tabletsPerIntake(String dose) { + if (dose == null) return 1; + String d = dose.trim().toLowerCase(); + if (d.startsWith("half")) return 0.5; + if (d.startsWith("one & half") || d.startsWith("one and half") || d.startsWith("1.5")) return 1.5; + if (d.startsWith("two")) return 2; + return 1; + } + + // ItemID, ItemName, strength+UOM, form, route, isEDL, IssueType, ItemFormID — only if the drug is mapped to + // the store on its own service line (same join as v_drugforprescription, so the save accepts what the list shows). + private Object[] getStoreItem(Integer facilityID, Integer drugID) { + List rows = em.createNativeQuery("SELECT i.ItemID, i.ItemName, CONCAT_WS(' ', i.Strength, u.UOMName), " + + "f.ItemFormName, r.RouteName, i.isEDL, c.IssueType, i.ItemFormID " + + "FROM db_iemr.m_item i " + + "JOIN db_iemr.m_itemfacilitymapping m ON m.ItemID = i.ItemID AND m.FacilityID = :facilityID " + + "AND m.ProviderServiceMapID = i.ProviderServiceMapID AND m.Deleted = false " + + "LEFT JOIN db_iemr.m_uom u ON u.UOMID = i.UOMID " + + "LEFT JOIN db_iemr.m_itemform f ON f.ItemFormID = i.ItemFormID " + + "LEFT JOIN db_iemr.m_routeofadmin r ON r.RouteID = i.RouteID " + + "LEFT JOIN db_iemr.m_itemcategory c ON c.ItemCategoryID = i.ItemCategoryID " + + "WHERE i.ItemID = :drugID AND i.Deleted = false") + .setParameter("facilityID", facilityID) + .setParameter("drugID", drugID) + .getResultList(); + if (rows.isEmpty()) { + throw new IllegalArgumentException("drugID " + drugID + " is not available in this camp's store"); + } + return (Object[]) rows.get(0); + } + + // A batch is usable if it has no expiry date (counted by v_drugforprescription too) or lasts the course. + private static final String USABLE_BATCH = "AND (ExpiryDate IS NULL OR ExpiryDate > DATE_ADD(CURDATE(), INTERVAL :days DAY)) "; + + // Usable batches (VanSerialNo, QuantityInHand), locked for this transaction, in the category's issue order. + @SuppressWarnings("unchecked") + private List lockBatches(Integer facilityID, Integer drugID, String issueType, int durationDays) { + String order; + if ("Last In First Out".equalsIgnoreCase(issueType)) order = "CreatedDate DESC, ItemStockEntryID DESC"; + else if ("First In First Out".equalsIgnoreCase(issueType)) order = "CreatedDate ASC, ItemStockEntryID ASC"; + else order = "ExpiryDate IS NULL, ExpiryDate ASC, ItemStockEntryID ASC"; // First Expiry First Out (default) + Query q = em.createNativeQuery("SELECT VanSerialNo, QuantityInHand FROM db_iemr.t_itemstockentry " + + "WHERE FacilityID = :facilityID AND ItemID = :drugID AND Deleted = false AND QuantityInHand > 0 " + + USABLE_BATCH + "ORDER BY " + order + " FOR UPDATE") + .setParameter("facilityID", facilityID) + .setParameter("drugID", drugID) + .setParameter("days", durationDays); + return (List) q.getResultList(); + } + + private int availableQuantity(Integer facilityID, Integer drugID, int durationDays) { + Object v = em.createNativeQuery("SELECT COALESCE(SUM(QuantityInHand), 0) FROM db_iemr.t_itemstockentry " + + "WHERE FacilityID = :facilityID AND ItemID = :drugID AND Deleted = false AND QuantityInHand > 0 " + + USABLE_BATCH) + .setParameter("facilityID", facilityID) + .setParameter("drugID", drugID) + .setParameter("days", durationDays) + .getSingleResult(); + return ((Number) v).intValue(); + } + + private Integer getStorePsm(Integer facilityID) { + Object v = em.createNativeQuery("SELECT ProviderServiceMapID FROM db_iemr.m_facility WHERE FacilityID = :facilityID") + .setParameter("facilityID", facilityID) + .getSingleResult(); + return v != null ? ((Number) v).intValue() : null; + } + + // Longest treatment among the lines for this drug, so the batch lasts until the course ends. + private int maxDurationDays(List> drugs, Integer drugID) { + int max = 0; + for (Map d : drugs) { + if (!drugID.equals(toInt(d.get("drugID")))) continue; + Integer n = toInt(d.get("duration")); + if (n == null || n <= 0) continue; + String unit = Optional.ofNullable(toStr(d.get("durationUnit"))).orElse("Day").toLowerCase(); + int days = unit.startsWith("week") ? n * 7 : unit.startsWith("month") ? n * 30 : unit.startsWith("year") ? n * 365 : n; + max = Math.max(max, days); + } + return max; + } + + private long lastInsertId() { + return ((Number) em.createNativeQuery("SELECT LAST_INSERT_ID()").getSingleResult()).longValue(); + } + + // VanSerialNo = own ID, as every MMU/Inventory save does, so van-to-server sync can identify the row. + private void stampVanSerialNo(String table, String idColumn, long id) { + em.createNativeQuery("UPDATE db_iemr." + table + " SET VanSerialNo = " + idColumn + " WHERE " + idColumn + " = :id") + .setParameter("id", id) + .executeUpdate(); + } + + @SuppressWarnings("unchecked") + private List> toList(Object v) { + if (v instanceof List) return (List>) v; + return Collections.emptyList(); + } + + private Integer toInt(Object v) { + if (v == null) return null; + if (v instanceof Number) return ((Number) v).intValue(); + String s = v.toString().trim(); + if (s.isEmpty()) return null; + try { + return (int) Double.parseDouble(s); + } catch (NumberFormatException e) { + return null; + } + } + + private String toStr(Object v) { + return v != null ? v.toString() : null; + } +} diff --git a/src/main/java/com/iemr/flw/service/StopTBService.java b/src/main/java/com/iemr/flw/service/StopTBService.java index e549daa6f..4011d4315 100644 --- a/src/main/java/com/iemr/flw/service/StopTBService.java +++ b/src/main/java/com/iemr/flw/service/StopTBService.java @@ -1,5 +1,6 @@ package com.iemr.flw.service; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -19,4 +20,15 @@ public interface StopTBService { // Nurse — Diagnostics List> saveDiagnostics(List> dataList) throws Exception; Map getAllDiagnostics(Integer providerServiceMapID, Integer villageID) throws Exception; + + // The same records the getAll endpoints return, for specific rows (STOP-TB changes feed), keyed by + // the row id. Deleted rows, and rows getAll would not return, are left out. + Map> getNurseTBScreeningsByIds(Collection ids); + Map> getGeneralExaminationsByIds(Collection ids); + Map> getDiagnosticsByIds(Collection ids); + // Standard-table OPD visits, keyed by BenVisitID + Map> getGeneralOpdByVisitIds(Collection benVisitIds); + // Older free-text OPD rows (tb_stoptb_general_opd), keyed by their id; left out when the same visit + // also exists in the standard tables, as getAllGeneralOpd does + Map> getLegacyGeneralOpdByIds(Collection ids); } diff --git a/src/main/java/com/iemr/flw/service/StopTBSyncService.java b/src/main/java/com/iemr/flw/service/StopTBSyncService.java new file mode 100644 index 000000000..9e8c94b6a --- /dev/null +++ b/src/main/java/com/iemr/flw/service/StopTBSyncService.java @@ -0,0 +1,19 @@ +package com.iemr.flw.service; + +import java.util.List; +import java.util.Map; + +public interface StopTBSyncService { + + /** + * One page of the STOP-TB changes feed for the given villages: a first full download when the + * token is missing, from another hub or too old; otherwise only what changed after it. + * Returns {supported:false} where the change log isn't installed, so the app keeps its full pull. + * The service and villages must be mapped to userId (from the JWT); empty villageIds means all of + * the user's villages for that service. + * types limits the feed to the record types the app applies (StopTBSyncType api names); null or + * empty means all. The app must start a new snapshot (no token) whenever it changes this list. + */ + Map getChanges(Integer userId, String token, Integer providerServiceMapID, List villageIds, + List types, Integer limit, String authorisation); +} diff --git a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java index 23871f1b2..b1d4165eb 100644 --- a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java +++ b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java @@ -1,8 +1,6 @@ package com.iemr.flw.service; import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; -import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; -import com.iemr.flw.dto.iemr.TbTptFollowUpDTO; import org.springframework.stereotype.Service; import java.util.List; @@ -18,11 +16,6 @@ public interface TBConfirmedCaseService { String getByProviderServiceMapId(Integer providerServiceMapID, Integer villageID) throws Exception; - String saveReferralFollowUp(TbReferralFollowUpDTO requestDTO, String token); - - String getReferralFollowUp(String token); - - String saveTptFollowUp(TbTptFollowUpDTO requestDTO, String token); - - String getTptFollowUp(String token); + // One record per row, in the same JSON shape getAll returns (STOP-TB changes feed), keyed by id. + java.util.Map getRecordsByIds(java.util.Collection ids); } diff --git a/src/main/java/com/iemr/flw/service/TBSuspectedService.java b/src/main/java/com/iemr/flw/service/TBSuspectedService.java index 32d882a80..97d9e0d87 100644 --- a/src/main/java/com/iemr/flw/service/TBSuspectedService.java +++ b/src/main/java/com/iemr/flw/service/TBSuspectedService.java @@ -13,4 +13,7 @@ public interface TBSuspectedService { String save(TBSuspectedRequestDTO tbScreeningList) throws Exception; String getByUserId(GetBenRequestHandler userId); + + // One record per row, in the same JSON shape getAll returns (STOP-TB changes feed), keyed by id. + java.util.Map getRecordsByIds(java.util.Collection ids); } 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 dda2bb9d1..bc1edc372 100644 --- a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -119,6 +120,9 @@ public class BeneficiaryServiceImpl implements BeneficiaryService { @Autowired private BenPhysicalVitalRepo benPhysicalVitalRepo; + @Autowired + private WorklistPagePrefetch worklistPagePrefetch; + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); @@ -141,8 +145,10 @@ public String getBenData(GetBenRequestHandler request, String authorisation) thr // O(village size), on every page including page 0. See BeneficiaryRepo for the // underlying query. if (request.getProviderServiceMapID() != null && request.getVillageID() != null) { + long tStart = System.currentTimeMillis(); long totalCount = beneficiaryRepo.countVillageWorklist( request.getProviderServiceMapID(), request.getVillageID()); + long tCount = System.currentTimeMillis(); if (totalCount == 0) return null; @@ -152,6 +158,7 @@ public String getBenData(GetBenRequestHandler request, String authorisation) thr List addressIds = beneficiaryRepo.getVillageWorklistAddressIds( request.getProviderServiceMapID(), request.getVillageID(), pageSize, offset); + long tIds = System.currentTimeMillis(); if (addressIds.isEmpty()) return null; @@ -159,17 +166,28 @@ public String getBenData(GetBenRequestHandler request, String authorisation) thr // Hibernate 6.4.1 bug there: "Binding is multi-valued; illegal call to // #getBindValue" even with a well-formed, non-empty id list (confirmed live // against 192.168.45.40 - the 10 rows returned have no NULLs/type issues, so - // this isn't a data problem). Looping getAddressById() per id sidesteps - // Hibernate's collection-parameter binding entirely - only ever pageSize (10) - // calls per page, same order-preservation as before. - List pageAddresses = addressIds.stream() - .map(beneficiaryRepo::getAddressById) - .filter(java.util.Objects::nonNull) - .collect(Collectors.toList()); + // this isn't a data problem). WorklistPagePrefetch reads them in one native query + // with the ids as numeric literals (no collection binding), keeping page order; + // the per-id loop stays as the fallback. + List pageAddresses; + try { + pageAddresses = worklistPagePrefetch.addressesInOrder(addressIds); + } catch (Exception e) { + logger.warn("Worklist address batch failed, reading one by one: " + e.getMessage()); + pageAddresses = addressIds.stream() + .map(beneficiaryRepo::getAddressById) + .filter(java.util.Objects::nonNull) + .collect(Collectors.toList()); + } if (pageAddresses.isEmpty()) return null; + long tAddr = System.currentTimeMillis(); - return getMappingsForAddressIDs(pageAddresses, totalPage, authorisation); + String timingLabel = "[WORKLIST-TIMING] psm=" + request.getProviderServiceMapID() + + " village=" + request.getVillageID() + " page=" + request.getPageNo() + "/" + totalPage + + " pageSize=" + pageSize + " villageTotal=" + totalCount + + " | countMs=" + (tCount - tStart) + " idsMs=" + (tIds - tCount) + " addressMs=" + (tAddr - tIds); + return getMappingsForAddressIDs(pageAddresses, totalPage, authorisation, timingLabel, tStart); } // Normal FLW/ASHA path @@ -213,13 +231,59 @@ public String getBenData(GetBenRequestHandler request, String authorisation) thr return getMappingsForAddressIDs( pageResult.getContent(), pageResult.getTotalPages(), - authorisation + authorisation, + null, + 0L ); } + // timingLabel != null logs one [WORKLIST-TIMING] line per page (Stop TB village path) so camp-laptop + // logs show where each page's time goes. private String getMappingsForAddressIDs(List addressList, int totalPage, - String authorisation) { + String authorisation, String timingLabel, long tStart) { + long tBuildStart = System.currentTimeMillis(); + List> resultList = buildBeneficiaryRecords(addressList, authorisation); + long tBuild = System.currentTimeMillis(); + + Map response = new HashMap<>(); + response.put("data", resultList); + response.put("pageSize", Integer.parseInt(door_to_door_page_size)); + response.put("totalPage", totalPage); + Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + String json = gson.toJson(response); + + if (timingLabel != null) { + long tEnd = System.currentTimeMillis(); + logger.info(timingLabel + " buildMs=" + (tBuild - tBuildStart) + " jsonMs=" + (tEnd - tBuild) + + " totalMs=" + (tEnd - tStart) + " rows=" + resultList.size() + "/" + addressList.size() + + " bytes=" + json.length()); + } + return json; + } + + // One record per beneficiary, in the same JSON shape getBeneficiaryData returns, keyed by BenRegId. + // Used by the STOP-TB changes feed; a BenRegId with no mapping or address is left out. + @Override + public Map getBeneficiaryRecordsByRegIds(List benRegIds, String authorisation) { + List addresses = new ArrayList<>(); + for (Long benRegId : benRegIds) { + RMNCHMBeneficiarymapping m = beneficiaryRepo.getById(BigInteger.valueOf(benRegId)); + if (m == null || m.getBenAddressId() == null) continue; + RMNCHMBeneficiaryaddress a = beneficiaryRepo.getAddressById(m.getBenAddressId()); + if (a != null) addresses.add(a); + } + Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + Map records = new LinkedHashMap<>(); + for (Map record : buildBeneficiaryRecords(addresses, authorisation)) { + Object benRegId = record.get("BenRegId"); + if (benRegId != null) records.put(new BigInteger(benRegId.toString()).longValue(), gson.toJson(record)); + } + return records; + } + + private List> buildBeneficiaryRecords(List addressList, + String authorisation) { RMNCHHouseHoldDetails benHouseHoldRMNCH_ROBJ; RMNCHBeneficiaryDetailsRmnch benDetailsRMNCH_OBJ; RMNCHBornBirthDetails benBotnBirthRMNCH_ROBJ; @@ -233,10 +297,20 @@ private String getMappingsForAddressIDs(List addressLi Map resultMap; ArrayList> resultList = new ArrayList<>(); + // One query per table for the whole page; if it fails, every lookup below falls back to its + // original per-beneficiary query. + WorklistPagePrefetch.Page pf = null; + try { + pf = worklistPagePrefetch.load(addressList); + } catch (Exception e) { + logger.warn("Worklist page prefetch failed, using per-beneficiary queries: " + e.getMessage()); + } + for (RMNCHMBeneficiaryaddress a : addressList) { // exception by-passing try { - List mappingsForAddress = beneficiaryRepo.getByAddressID(a.getId()); + List mappingsForAddress = pf != null ? pf.mappings(a.getId()) + : beneficiaryRepo.getByAddressID(a.getId()); if(!mappingsForAddress.isEmpty()){ RMNCHMBeneficiarymapping m = mappingsForAddress.get(0); if (m != null) { @@ -249,38 +323,53 @@ private String getMappingsForAddressIDs(List addressLi benImageOBJ = new RMNCHMBeneficiaryImage(); benAddressOBJ = new RMNCHMBeneficiaryaddress(); benContactOBJ = new RMNCHMBeneficiarycontact(); - Map healthDetails = getBenHealthDetails(m.getBenRegId()); + Long regIdLong = m.getBenRegId() != null ? m.getBenRegId().longValue() : null; + // no m_benhealthidmapping row -> the original lookup returns an empty map too + Map healthDetails = (pf != null && regIdLong != null && !pf.hasHealthId(regIdLong)) + ? new HashMap<>() : getBenHealthDetails(m.getBenRegId()); if (m.getBenDetailsId() != null) { - benDetailsOBJ = beneficiaryRepo.getDetailsById(m.getBenDetailsId()); + benDetailsOBJ = pf != null ? pf.detail(m.getBenDetailsId()) + : beneficiaryRepo.getDetailsById(m.getBenDetailsId()); } if (m.getBenAccountID() != null) { - benAccountOBJ = beneficiaryRepo.getAccountById(m.getBenAccountID()); + benAccountOBJ = pf != null ? pf.account(m.getBenAccountID()) + : beneficiaryRepo.getAccountById(m.getBenAccountID()); } if (m.getBenImageId() != null) { - benImageOBJ = beneficiaryRepo.getImageById(m.getBenImageId().longValue()); + benImageOBJ = pf != null ? pf.image(m.getBenImageId()) + : beneficiaryRepo.getImageById(m.getBenImageId().longValue()); } if (m.getBenAddressId() != null) { - benAddressOBJ = beneficiaryRepo.getAddressById(m.getBenAddressId()); + benAddressOBJ = pf != null ? pf.address(m.getBenAddressId()) + : beneficiaryRepo.getAddressById(m.getBenAddressId()); } if (m.getBenContactsId() != null) { - benContactOBJ = beneficiaryRepo.getContactById(m.getBenContactsId()); + benContactOBJ = pf != null ? pf.contact(m.getBenContactsId()) + : beneficiaryRepo.getContactById(m.getBenContactsId()); } BigInteger benID = null; - if (m.getBenRegId() != null) - benID = beneficiaryRepo.getBenIdFromRegID(m.getBenRegId().longValue()); + if (regIdLong != null) { + // more than one row: let the original single-result query decide, as before + benID = (pf != null && pf.benIds(regIdLong).size() <= 1) + ? pf.benIds(regIdLong).stream().findFirst().orElse(null) + : beneficiaryRepo.getBenIdFromRegID(regIdLong); + } - if (m.getBenRegId() != null) { - List detailsByRegID = beneficiaryRepo - .getDetailsByRegID((m.getBenRegId()).longValue()); + if (regIdLong != null) { + List detailsByRegID = pf != null ? pf.rmnch(regIdLong) + : beneficiaryRepo.getDetailsByRegID(regIdLong); if(!detailsByRegID.isEmpty()){ benDetailsRMNCH_OBJ = detailsByRegID.get(0); } - benBotnBirthRMNCH_ROBJ = beneficiaryRepo.getBornBirthByRegID((m.getBenRegId()).longValue()); + benBotnBirthRMNCH_ROBJ = (pf != null && pf.bornBirth(regIdLong).size() <= 1) + ? pf.bornBirth(regIdLong).stream().findFirst().orElse(null) + : beneficiaryRepo.getBornBirthByRegID(regIdLong); if (benDetailsRMNCH_OBJ != null && benDetailsRMNCH_OBJ.getHouseoldId() != null) { - List householdsById = houseHoldRepo - .getByHouseHoldID(benDetailsRMNCH_OBJ.getHouseoldId()); + List householdsById = pf != null + ? pf.households(benDetailsRMNCH_OBJ.getHouseoldId()) + : houseHoldRepo.getByHouseHoldID(benDetailsRMNCH_OBJ.getHouseoldId()); if(!householdsById.isEmpty()){ benHouseHoldRMNCH_ROBJ = householdsById.get(0); } @@ -363,7 +452,6 @@ private String getMappingsForAddressIDs(List addressLi if (benAddressOBJ.getPermPinCode() != null) benDetailsRMNCH_OBJ.setPinCode(benAddressOBJ.getPermPinCode()); - // ----------------------------------------------------------------------------- // related benids @@ -393,7 +481,8 @@ private String getMappingsForAddressIDs(List addressLi } else { // i_beneficiarydetails.dob is null for Stop TB mobile registrations // (Identity-API mapper commented out) — fall back to i_ben_flow_outreach.ben_dob - List flows = benFlowStatusRepo.findByBeneficiaryRegID(m.getBenRegId().longValue()); + List flows = pf != null ? pf.flows(regIdLong) + : benFlowStatusRepo.findByBeneficiaryRegID(m.getBenRegId().longValue()); if (!flows.isEmpty() && flows.get(0).getDob() != null) benDetailsRMNCH_OBJ.setDob(flows.get(0).getDob()); } @@ -530,39 +619,39 @@ private String getMappingsForAddressIDs(List addressLi if (benDetailsOBJ != null && benDetailsOBJ.getOccupation() != null) benDetailsRMNCH_OBJ.setOccupation(benDetailsOBJ.getOccupation()); - // anthropometry from t_phy_anthropometry, vitals from t_phy_vitals - // fallback to otherFields if exam not yet saved for this beneficiary + // anthropometry from t_phy_anthropometry, vitals from t_phy_vitals — latest non-null + // value per field, so a later row with some columns empty doesn't hide older values. + // otherFields fills whatever is still missing (beneficiaries registered before + // Identity-API started writing these tables). Long benRegIdLong = m.getBenRegId() != null ? m.getBenRegId().longValue() : null; if (benRegIdLong != null) { - List anthroList = - benAnthropometryRepo.findByBeneficiaryRegIDOrderByCreatedDateDesc(benRegIdLong); - List vitalList = - benPhysicalVitalRepo.findByBeneficiaryRegIDOrderByCreatedDateDesc(benRegIdLong); + List anthroList = pf != null ? pf.anthropometry(benRegIdLong) + : benAnthropometryRepo.findByBeneficiaryRegIDOrderByCreatedDateDesc(benRegIdLong); + List vitalList = pf != null ? pf.vitals(benRegIdLong) + : benPhysicalVitalRepo.findByBeneficiaryRegIDOrderByCreatedDateDesc(benRegIdLong); Map anthropometry = new HashMap<>(); - if (!anthroList.isEmpty()) { - BenAnthropometryDetail anthro = anthroList.get(0); - if (anthro.getHeightCm() != null) anthropometry.put("height", anthro.getHeightCm()); - if (anthro.getWeightKg() != null) anthropometry.put("weight", anthro.getWeightKg()); - if (anthro.getBmi() != null) anthropometry.put("bmi", anthro.getBmi()); + for (BenAnthropometryDetail anthro : anthroList) { + if (anthro.getHeightCm() != null) anthropometry.putIfAbsent("height", anthro.getHeightCm()); + if (anthro.getWeightKg() != null) anthropometry.putIfAbsent("weight", anthro.getWeightKg()); + if (anthro.getBmi() != null) anthropometry.putIfAbsent("bmi", anthro.getBmi()); } - if (!vitalList.isEmpty()) { - BenPhysicalVitalDetail vital = vitalList.get(0); - if (vital.getTemperature() != null) anthropometry.put("temperatureValue", vital.getTemperature()); - if (vital.getPulseRate() != null) anthropometry.put("pulseRate", vital.getPulseRate()); - if (vital.getSystolicBP() != null) anthropometry.put("systolicBP", vital.getSystolicBP()); - if (vital.getDiastolicBP() != null) anthropometry.put("diastolicBP", vital.getDiastolicBP()); - if (vital.getBloodGlucoseRandom() != null) anthropometry.put("bloodGlucoseRandom", vital.getBloodGlucoseRandom()); + for (BenPhysicalVitalDetail vital : vitalList) { + if (vital.getTemperature() != null) anthropometry.putIfAbsent("temperatureValue", vital.getTemperature()); + if (vital.getPulseRate() != null) anthropometry.putIfAbsent("pulseRate", vital.getPulseRate()); + if (vital.getSystolicBP() != null) anthropometry.putIfAbsent("systolicBP", vital.getSystolicBP()); + if (vital.getDiastolicBP() != null) anthropometry.putIfAbsent("diastolicBP", vital.getDiastolicBP()); + if (vital.getBloodGlucoseRandom() != null) anthropometry.putIfAbsent("bloodGlucoseRandom", vital.getBloodGlucoseRandom()); } - // fallback: if no exam saved yet, read from registration otherFields - if (anthropometry.isEmpty() && benDetailsOBJ != null && benDetailsOBJ.getOtherFields() != null) { + // fallback per field: registration otherFields + if (benDetailsOBJ != null && benDetailsOBJ.getOtherFields() != null) { try { Map extraFields = new Gson().fromJson(benDetailsOBJ.getOtherFields(), Map.class); - if (extraFields.containsKey("weight")) anthropometry.put("weight", extraFields.get("weight")); - if (extraFields.containsKey("height")) anthropometry.put("height", extraFields.get("height")); - if (extraFields.containsKey("bmi")) anthropometry.put("bmi", extraFields.get("bmi")); - if (extraFields.containsKey("temperatureValue")) anthropometry.put("temperatureValue", extraFields.get("temperatureValue")); + if (extraFields.get("weight") != null) anthropometry.putIfAbsent("weight", extraFields.get("weight")); + if (extraFields.get("height") != null) anthropometry.putIfAbsent("height", extraFields.get("height")); + if (extraFields.get("bmi") != null) anthropometry.putIfAbsent("bmi", extraFields.get("bmi")); + if (extraFields.get("temperatureValue") != null) anthropometry.putIfAbsent("temperatureValue", extraFields.get("temperatureValue")); } catch (Exception ex) { logger.warn("Could not parse otherFields for fallback anthropometry: " + benDetailsOBJ.getBeneficiaryDetailsId()); } @@ -595,13 +684,24 @@ private String getMappingsForAddressIDs(List addressLi // adding asha id / created by - user id if (benAddressOBJ.getCreatedBy() != null) { - Integer userID = beneficiaryRepo.getUserIDByUserName(benAddressOBJ.getCreatedBy()); + String createdBy = benAddressOBJ.getCreatedBy(); + Integer userID; + if (pf != null && pf.userIdCache().containsKey(createdBy)) { + userID = pf.userIdCache().get(createdBy); + } else { + userID = beneficiaryRepo.getUserIDByUserName(createdBy); + if (pf != null) pf.userIdCache().put(createdBy, userID); + } if (userID != null && userID > 0) resultMap.put("ashaId", userID); } - // get HealthID of ben - if (m.getBenRegId() != null) { - fetchHealthIdByBenRegID(m.getBenRegId().longValue(), authorisation, resultMap); + // get HealthID of ben: read locally (same table FHIR-API reads), only when a mapping exists + if (regIdLong != null) { + if (pf != null) { + if (pf.hasHealthId(regIdLong)) putLocalHealthId(regIdLong, resultMap); + } else { + fetchHealthIdByBenRegID(regIdLong, authorisation, resultMap); + } } resultList.add(resultMap); @@ -617,13 +717,7 @@ private String getMappingsForAddressIDs(List addressLi logger.error("error for addressID :" + e.getMessage() + a.getId() + " and vanID : " + a.getVanID()); } } - - Map response = new HashMap<>(); - response.put("data", resultList); - response.put("pageSize", Integer.parseInt(door_to_door_page_size)); - response.put("totalPage", totalPage); - Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); - return gson.toJson(response); + return resultList; } @@ -671,6 +765,22 @@ private Map getBenBenVisitDetails(BigInteger benRegId) { return healthDetails; } + // Mirrors FHIR-API HealthIDServiceImpl.getBenHealthID: every m_benhealthidmapping row, with healthId + // replaced by t_healthid.HealthId when that is filled; the last row wins, as in fetchHealthIdByBenRegID. + private void putLocalHealthId(Long benRegID, Map resultMap) { + for (Object[] row : beneficiaryRepo.getHealthIdMappingRows(benRegID)) { + String healthId = row[0] != null ? row[0].toString() : null; + String healthIdNumber = row[1] != null ? row[1].toString() : null; + if (healthIdNumber != null) { + List fromHealthIdTable = beneficiaryRepo.getHealthIdByNumber(healthIdNumber); + if (!fromHealthIdTable.isEmpty() && fromHealthIdTable.get(0) != null && !fromHealthIdTable.get(0).isEmpty()) + healthId = fromHealthIdTable.get(0); + } + if (healthId != null) resultMap.put("healthId", healthId); + if (healthIdNumber != null) resultMap.put("healthIdNumber", healthIdNumber); + } + } + public void fetchHealthIdByBenRegID(Long benRegID, String authorization, Map resultMap) { Map requestMap = new HashMap(); requestMap.put("beneficiaryRegID", benRegID); diff --git a/src/main/java/com/iemr/flw/service/impl/DiagnosticDocumentServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiagnosticDocumentServiceImpl.java index b0f92ab4e..6c0f1f586 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiagnosticDocumentServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiagnosticDocumentServiceImpl.java @@ -116,7 +116,7 @@ public DiagnosticDocumentContent fetch(Long beneficiaryId, DiagnosticDocumentTyp String orderType = documentType.impliedOrderType().name(); DiagnosticOrder order; if (visitCode != null) { - order = diagnosticOrderRepo.findByBeneficiaryIdAndVisitCodeAndOrderType(beneficiaryId, visitCode, orderType) + order = diagnosticOrderRepo.findFirstByBeneficiaryIdAndVisitCodeAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, visitCode, orderType) .orElseThrow(() -> new Exception("No diagnostic order found for beneficiaryId=" + beneficiaryId + ", visitCode=" + visitCode + ", orderType=" + orderType)); } else { diff --git a/src/main/java/com/iemr/flw/service/impl/DiagnosticOrderServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiagnosticOrderServiceImpl.java index 1485843e6..913a747a2 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiagnosticOrderServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiagnosticOrderServiceImpl.java @@ -1,13 +1,16 @@ package com.iemr.flw.service.impl; +import com.iemr.flw.domain.iemr.BenVisitDetail; import com.iemr.flw.domain.iemr.DiagnosticOrder; import com.iemr.flw.domain.iemr.DiagnosticResult; import com.iemr.flw.domain.iemr.TBSuspected; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.dto.DiagnosticOrderRequestDto; import com.iemr.flw.dto.DiagnosticOrderResultDto; import com.iemr.flw.dto.DiagnosticOrderStatusSummaryDto; import com.iemr.flw.dto.ManualDiagnosticResultRequestDto; import com.iemr.flw.dto.VendorHealthDto; +import com.iemr.flw.integration.provider.DiagnosticCancelResult; import com.iemr.flw.integration.provider.DiagnosticDocumentAsset; import com.iemr.flw.integration.provider.DiagnosticPollResult; import com.iemr.flw.integration.provider.DiagnosticProvider; @@ -15,12 +18,19 @@ import com.iemr.flw.integration.provider.DiagnosticPushResult; import com.iemr.flw.masterEnum.DiagnosticOrderStatus; import com.iemr.flw.masterEnum.DiagnosticOrderType; +import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.DiagnosticOrderRepo; import com.iemr.flw.repo.iemr.DiagnosticResultRepo; +import com.iemr.flw.repo.iemr.EmployeeMasterRepo; import com.iemr.flw.repo.iemr.TBSuspectedRepo; import com.iemr.flw.service.CampConfigService; import com.iemr.flw.service.DiagnosticDocumentService; import com.iemr.flw.service.DiagnosticOrderService; +import com.iemr.flw.service.TBStopVisitService; +import com.iemr.flw.utils.JwtUtil; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -28,9 +38,15 @@ import org.springframework.stereotype.Service; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; @Service public class DiagnosticOrderServiceImpl implements DiagnosticOrderService { @@ -39,11 +55,27 @@ public class DiagnosticOrderServiceImpl implements DiagnosticOrderService { private static final Set BLOCKING_STATUSES = Set.of( DiagnosticOrderStatus.PENDING.name(), - DiagnosticOrderStatus.IN_PROGRESS.name(), - DiagnosticOrderStatus.EXPIRED.name(), DiagnosticOrderStatus.COMPLETED.name(), DiagnosticOrderStatus.MANUAL_ENTRY.name()); + private static final Set NON_REUSABLE_ON_CLOSE_STATUSES = Set.of( + DiagnosticOrderStatus.COMPLETED.name(), + DiagnosticOrderStatus.FAILED.name(), + DiagnosticOrderStatus.CLOSED.name()); + + // Statuses the scheduler polls and the daily cutoff expires — matches findXrayDueForPoll / + // findTrueNatDueForPoll / findAllOutstandingOrders. + private static final Set OUTSTANDING_STATUSES = Set.of( + DiagnosticOrderStatus.PENDING.name(), + DiagnosticOrderStatus.IN_PROGRESS.name()); + + // Invalid test outcomes: the result is still recorded (result row, tb_suspected write-back, documents) + // but the order is CLOSED instead of COMPLETED, so a retest can be pushed. The vendor reports an + // invalid MTB/MDR_RIF run as "Error-2"; a manual entry uses "Invalid/Error". + private static final String XRAY_INVALID_RESULT = "AI Invalid Result"; + private static final String SPUTUM_INVALID_POLLED_RESULT = "Error-2"; + private static final String SPUTUM_INVALID_MANUAL_RESULT = "Invalid/Error"; + @Autowired private DiagnosticOrderRepo diagnosticOrderRepo; @@ -62,10 +94,109 @@ public class DiagnosticOrderServiceImpl implements DiagnosticOrderService { @Autowired private CampConfigService campConfigService; + @Autowired + private BeneficiaryRepo beneficiaryRepo; + + @Autowired + private TBStopVisitService tbStopVisitService; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private EmployeeMasterRepo employeeMasterRepo; + @Override - public DiagnosticOrder createAndPushOrder(DiagnosticOrderRequestDto request) throws Exception { + public DiagnosticOrder createAndPushOrderByUser(DiagnosticOrderRequestDto request, String jwtToken) throws Exception { + return createAndPushOrder(request, resolveActingUserName(jwtToken)); + } + + private String resolveActingUserName(String jwtToken) { + try { + User user = employeeMasterRepo.findUserByUserID(jwtUtil.extractUserId(jwtToken)); + if (user != null && user.getUserName() != null && !user.getUserName().isBlank()) { + return user.getUserName(); + } + } catch (Exception e) { + logger.warn("Could not resolve acting user's username from m_user: {}", e.getMessage()); + } + return jwtUtil.extractUsername(jwtToken); + } + + @Override + public DiagnosticOrder createAndPushOrderAsSystem(DiagnosticOrderRequestDto request) throws Exception { + return createAndPushOrder(request, "SYSTEM"); + } + + // One lock per beneficiary, held across visit lookup → dedup check → insert → vendor push. Without it, + // two simultaneous pushes for the same beneficiary could both pass the dedup check (or both create a + // visit for today) and send the same patient to the vendor twice — shown as duplicate names on the + // TrueNat machine. Keyed by beneficiary, not orderType, because the visit is shared across order types. + // (release-3.9.3 keys its lock by beneficiary+orderType because there the client supplies the + // visitCode; here the server creates the visit, so the key must be the beneficiary alone.) + // In-memory, so it only serialises within this JVM: correct while orders are created only by the + // single van server that can reach the vendor. Same mechanism as release-3.9.3: one ReentrantLock per + // beneficiary, held weakly so an idle beneficiary's lock is garbage-collected — any thread waiting on + // or holding it keeps a strong reference, so concurrent callers always share the same instance. + // User requests wait at most LOCK_WAIT_SECONDS and then fail with a retry message, instead of piling + // up behind a slow vendor push (bounded by the EmrLiteRestTemplateConfig timeouts). + private final LoadingCache beneficiaryOrderLocks = CacheBuilder.newBuilder() + .weakValues() + .build(CacheLoader.from(beneficiaryId -> new ReentrantLock())); + + private static final long LOCK_WAIT_SECONDS = 30; + + private T withBeneficiaryLock(Long beneficiaryId, Callable action) throws Exception { + Lock lock = beneficiaryLock(beneficiaryId); + if (!lock.tryLock(LOCK_WAIT_SECONDS, TimeUnit.SECONDS)) { + throw new IllegalStateException("Another diagnostic order operation is still in progress for beneficiaryId=" + + beneficiaryId + " — please retry shortly"); + } + try { + return action.call(); + } finally { + lock.unlock(); + } + } + + // For background work with no caller to retry it (the automatic retest): waits as long as it takes. + private T withBeneficiaryLockBlocking(Long beneficiaryId, Callable action) throws Exception { + Lock lock = beneficiaryLock(beneficiaryId); + lock.lock(); + try { + return action.call(); + } finally { + lock.unlock(); + } + } + + // For the poll scheduler: never waits. A busy beneficiary (user push/manual entry in progress) is + // simply left for the next tick, rather than stalling the single scheduler thread behind it. + private Optional withBeneficiaryLockIfFree(Long beneficiaryId, Callable action) throws Exception { + Lock lock = beneficiaryLock(beneficiaryId); + if (!lock.tryLock()) { + return Optional.empty(); + } + try { + return Optional.ofNullable(action.call()); + } finally { + lock.unlock(); + } + } + + private Lock beneficiaryLock(Long beneficiaryId) { + if (beneficiaryId == null) { + throw new IllegalArgumentException("beneficiaryId is required"); + } + return beneficiaryOrderLocks.getUnchecked(beneficiaryId); + } + + private DiagnosticOrder createAndPushOrder(DiagnosticOrderRequestDto request, String createdBy) throws Exception { + return withBeneficiaryLock(request.getBeneficiaryId(), () -> createAndPushOrderLocked(request, createdBy)); + } + + private DiagnosticOrder createAndPushOrderLocked(DiagnosticOrderRequestDto request, String createdBy) throws Exception { Long beneficiaryId = request.getBeneficiaryId(); - Long visitCode = request.getVisitCode(); DiagnosticOrderType orderType = DiagnosticOrderType.fromCode(request.getOrderType()); String orderEvent = request.getOrderEvent(); String patientFirstName = request.getPatient().getFirstName(); @@ -73,24 +204,43 @@ public DiagnosticOrder createAndPushOrder(DiagnosticOrderRequestDto request) thr String patientDateOfBirth = request.getPatient().getDateOfBirth(); String patientSex = request.getPatient().getSex(); - String providerCode = providerFactory.getProviderCodeForOrderType(orderType); - String externalOrderId = String.format("%d-%d-%s", beneficiaryId, visitCode, orderType.name()); - - String reasonForRefusal = request.getReasonForRefusal(); - if (reasonForRefusal != null) { - return saveRefusedOrder(beneficiaryId, visitCode, orderType, orderEvent, providerCode, externalOrderId, - patientFirstName, patientLastName, patientDateOfBirth, patientSex, reasonForRefusal); + String reasonToClose = request.getReasonToClose(); + if (reasonToClose != null) { + return closeOrder(beneficiaryId, orderType, orderEvent, patientFirstName, patientLastName, + patientDateOfBirth, patientSex, reasonToClose, createdBy); } + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + + Long beneficiaryRegID = beneficiaryRepo.getRegIDFromBenId(beneficiaryId); + if (beneficiaryRegID == null) { + throw new Exception("No beneficiaryRegID found for beneficiaryId=" + beneficiaryId); + } + BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, null, createdBy, vanID, + parkingPlaceID); + Long visitCode = visit.getVisitCode(); + + String providerCode = providerFactory.getProviderCodeForOrderType(orderType); + String externalOrderId = String.format("%s-%d-%s", UUID.randomUUID(), visitCode, orderType.name()); + Optional latestForType = diagnosticOrderRepo .findFirstByBeneficiaryIdAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, orderType.name()); Optional existing = (latestForType.isPresent() && visitCode.equals(latestForType.get().getVisitCode())) ? latestForType - : diagnosticOrderRepo.findByBeneficiaryIdAndVisitCodeAndOrderType(beneficiaryId, visitCode, orderType.name()); + : diagnosticOrderRepo.findFirstByBeneficiaryIdAndVisitCodeAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, visitCode, orderType.name()); - if (existing.isPresent() && !DiagnosticOrderStatus.FAILED.name().equals(existing.get().getStatus())) { - return existing.get(); + if (existing.isPresent()) { + String existingStatus = existing.get().getStatus(); + if (!DiagnosticOrderStatus.FAILED.name().equals(existingStatus) + && !DiagnosticOrderStatus.CLOSED.name().equals(existingStatus)) { + // Still active or already resolved (PENDING/COMPLETED/legacy IN_PROGRESS/MANUAL_ENTRY) + // — returned as-is. + return existing.get(); + } + // FAILED and CLOSED are never reused, even for the same visit — both stay as-is for + // history, and a fresh push always creates a brand new row instead of overwriting either. } if (latestForType.isPresent() @@ -98,16 +248,16 @@ public DiagnosticOrder createAndPushOrder(DiagnosticOrderRequestDto request) thr && !visitCode.equals(latestForType.get().getVisitCode())) { DiagnosticOrder blocker = latestForType.get(); logger.info("Duplicate order push suppressed for beneficiaryId={}, orderType={}: unresolved order id={} " - + "(visitCode={}, status={}) already exists — returning it instead of pushing a new order for visitCode={}", + + "(visitCode={}, status={}) already exists — returning it instead of pushing a new order for visitCode={}", beneficiaryId, orderType, blocker.getId(), blocker.getVisitCode(), blocker.getStatus(), visitCode); return blocker; } - DiagnosticOrder order = existing.orElseGet(DiagnosticOrder::new); - if (order.getVanID() == null) { - order.setVanID(campConfigService.getVanID()); - order.setParkingPlaceID(campConfigService.getParkingPlaceID()); - } + // Neither FAILED nor CLOSED is ever reused above, so this is always a brand new row — a + // beneficiary's diagnostic order history is a sequence of rows, not one row overwritten in place. + DiagnosticOrder order = new DiagnosticOrder(); + order.setVanID(vanID); + order.setParkingPlaceID(parkingPlaceID); order.setOrderEvent(orderEvent); order.setBeneficiaryId(beneficiaryId); order.setVisitCode(visitCode); @@ -115,20 +265,20 @@ public DiagnosticOrder createAndPushOrder(DiagnosticOrderRequestDto request) thr order.setProviderCode(providerCode); order.setOrderType(orderType.name()); order.setExternalOrderId(externalOrderId); - // Reset required when reusing a previously-FAILED row, otherwise a successful retry would - // leave status=FAILED and findDueForPoll (PENDING/IN_PROGRESS only) would never poll it. - order.setStatus(DiagnosticOrderStatus.PENDING.name()); - order.setErrorMessage(null); + boolean noVendor = providerCode == null || providerCode.isBlank(); + order.setStatus(noVendor ? DiagnosticOrderStatus.MANUAL_ENTRY.name() : DiagnosticOrderStatus.PENDING.name()); order.setPatientFirstName(patientFirstName); order.setPatientLastName(patientLastName); order.setPatientDateOfBirth(patientDateOfBirth); order.setPatientSex(patientSex); + order.setCreatedBy(createdBy); + order.setModifiedBy(createdBy); try { order = diagnosticOrderRepo.save(order); } catch (DataIntegrityViolationException dive) { Optional winner = diagnosticOrderRepo - .findByBeneficiaryIdAndVisitCodeAndOrderType(beneficiaryId, visitCode, orderType.name()); + .findFirstByBeneficiaryIdAndVisitCodeAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, visitCode, orderType.name()); if (winner.isPresent()) { logger.warn("Lost create race for beneficiaryId={}, visitCode={}, orderType={} — returning existing order id={}", beneficiaryId, visitCode, orderType, winner.get().getId()); @@ -137,15 +287,21 @@ public DiagnosticOrder createAndPushOrder(DiagnosticOrderRequestDto request) thr throw dive; } - if (providerCode == null || providerCode.isBlank()) { + if (noVendor) { logger.info("No active vendor configured for orderType={}, beneficiaryId={} — order saved for manual entry", orderType, beneficiaryId); - order.setStatus(DiagnosticOrderStatus.MANUAL_ENTRY.name()); + // Status is MANUAL_ENTRY (set above) — awaiting manual entry via submitManualResult. order = diagnosticOrderRepo.save(order); if (order.getVanSerialNo() == null) diagnosticOrderRepo.updateVanSerialNo(order.getId()); return order; } + return pushToProvider(order, providerCode); + } + + // Pushes an already-saved PENDING order to the vendor and saves the outcome — FAILED (with the + // error) if the push is rejected or throws. Shared by createAndPushOrder and pushRetestOrder. + private DiagnosticOrder pushToProvider(DiagnosticOrder order, String providerCode) { try { DiagnosticProvider provider = providerFactory.getProvider(providerCode); DiagnosticPushResult pushResult = provider.pushOrder(order); @@ -171,16 +327,57 @@ public DiagnosticOrder createAndPushOrder(DiagnosticOrderRequestDto request) thr return order; } + // Shared by createAndPushOrder (push with reasonToClose) and submitManualResult (manualResult + // with reasonToClose) — resolves the same visit/provider/externalOrderId a normal push would, then + // closes the order via saveRefusedOrder. Identical outcome regardless of which endpoint triggered it. + private DiagnosticOrder closeOrder(Long beneficiaryId, DiagnosticOrderType orderType, String orderEvent, + String patientFirstName, String patientLastName, String patientDateOfBirth, String patientSex, + String reasonToClose, String actingUserId) throws Exception { + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + + Long beneficiaryRegID = beneficiaryRepo.getRegIDFromBenId(beneficiaryId); + if (beneficiaryRegID == null) { + throw new Exception("No beneficiaryRegID found for beneficiaryId=" + beneficiaryId); + } + BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, null, actingUserId, vanID, + parkingPlaceID); + Long visitCode = visit.getVisitCode(); + + String providerCode = providerFactory.getProviderCodeForOrderType(orderType); + String externalOrderId = String.format("%s-%d-%s", UUID.randomUUID(), visitCode, orderType.name()); + return saveRefusedOrder(beneficiaryId, visitCode, orderType, orderEvent, providerCode, externalOrderId, + patientFirstName, patientLastName, patientDateOfBirth, patientSex, reasonToClose, actingUserId); + } + + // manualResult's reasonToClose variant has no patient/orderEvent in its request — it sources them + // from the beneficiary's own most recent order for this orderType (whatever its status), since that + // information already exists there. No prior order at all means there's nothing to source it from. + private DiagnosticOrder closeOrderManually(Long beneficiaryId, DiagnosticOrderType orderType, + String reasonToClose, String actingUserId) throws Exception { + return withBeneficiaryLock(beneficiaryId, () -> { + DiagnosticOrder source = diagnosticOrderRepo + .findFirstByBeneficiaryIdAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, orderType.name()) + .orElseThrow(() -> new Exception("No diagnostic order found for beneficiaryId=" + beneficiaryId + + ", orderType=" + orderType.name() + " — cannot close a record that was never created")); + return closeOrder(beneficiaryId, orderType, source.getOrderEvent(), source.getPatientFirstName(), + source.getPatientLastName(), source.getPatientDateOfBirth(), source.getPatientSex(), reasonToClose, + actingUserId); + }); + } + // Refusals are keyed to the latest order for this beneficiary+orderType (not the exact visitCode // of this request), since a refusal can be recorded outside the visit that originally created the - // order. A COMPLETED latest order is left untouched (treated as "not found") and a new REFUSED row - // is created instead. Refused orders are saved as-is and never pushed to the vendor. + // order. A COMPLETED, FAILED or already-CLOSED latest order is left untouched (treated as "not found") + // and a new CLOSED row is created instead, so its history (e.g. a FAILED row's errorMessage) survives. + // Refused orders are saved as-is and never pushed to the vendor. private DiagnosticOrder saveRefusedOrder(Long beneficiaryId, Long visitCode, DiagnosticOrderType orderType, - String orderEvent, String providerCode, String externalOrderId, String patientFirstName, - String patientLastName, String patientDateOfBirth, String patientSex, String reasonForRefusal) { + String orderEvent, String providerCode, String externalOrderId, String patientFirstName, + String patientLastName, String patientDateOfBirth, String patientSex, String reasonToClose, + String actingUserId) { Optional latest = diagnosticOrderRepo .findFirstByBeneficiaryIdAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, orderType.name()); - if (latest.isPresent() && DiagnosticOrderStatus.COMPLETED.name().equals(latest.get().getStatus())) { + if (latest.isPresent() && NON_REUSABLE_ON_CLOSE_STATUSES.contains(latest.get().getStatus())) { latest = Optional.empty(); } @@ -201,18 +398,23 @@ private DiagnosticOrder saveRefusedOrder(Long beneficiaryId, Long visitCode, Dia order.setPatientLastName(patientLastName); order.setPatientDateOfBirth(patientDateOfBirth); order.setPatientSex(patientSex); + order.setCreatedBy(actingUserId); } - order.setStatus(DiagnosticOrderStatus.REFUSED.name()); - order.setReasonToClose(reasonForRefusal); + order.setStatus(DiagnosticOrderStatus.CLOSED.name()); + order.setReasonToClose(reasonToClose); order.setErrorMessage(null); + order.setModifiedBy(actingUserId); + order.setManuallyEnteredBy(actingUserId); + order.setProcessed("N"); try { order = diagnosticOrderRepo.save(order); if (order.getVanSerialNo() == null) diagnosticOrderRepo.updateVanSerialNo(order.getId()); + notifyProviderOrderClosed(order, reasonToClose); return order; } catch (DataIntegrityViolationException dive) { Optional winner = diagnosticOrderRepo - .findByBeneficiaryIdAndVisitCodeAndOrderType(beneficiaryId, visitCode, orderType.name()); + .findFirstByBeneficiaryIdAndVisitCodeAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, visitCode, orderType.name()); if (winner.isPresent()) { logger.warn("Lost create race for beneficiaryId={}, visitCode={}, orderType={} — returning existing order id={}", beneficiaryId, visitCode, orderType, winner.get().getId()); @@ -222,10 +424,58 @@ private DiagnosticOrder saveRefusedOrder(Long beneficiaryId, Long visitCode, Dia } } + @Override + public void notifyProviderOrderClosed(DiagnosticOrder order, String reason) { + String providerCode = order.getProviderCode(); + if (providerCode == null || providerCode.isBlank()) { + return; // no vendor was ever involved (manual-entry order) + } + if (order.getPushResponseJson() == null || order.getPushResponseJson().isEmpty()) { + return; // never actually confirmed as pushed to the vendor — nothing to cancel there + } + try { + DiagnosticCancelResult result = providerFactory.getProvider(providerCode).cancelOrder(order, reason); + order.setCancelResponseJson(result.getRawResponseJson()); + order.setProcessed("N"); + diagnosticOrderRepo.save(order); + } catch (Exception e) { + // Transport-level failure only (unreachable, timeout) — a provider-level rejection is + // already captured in the returned result above, not thrown. + logger.warn("Failed to notify provider of order cancellation for externalOrderId={}: {}", + order.getExternalOrderId(), e.getMessage()); + } + } + @Override public DiagnosticOrderResultDto processResult(DiagnosticOrder order, DiagnosticPollResult pollResult) throws Exception { + return processResult(order, pollResult, false, "SYSTEM"); + } + + private DiagnosticOrderResultDto processResult(DiagnosticOrder order, DiagnosticPollResult pollResult, + boolean writeBackWhenClosed, String actingUser) throws Exception { Optional existingResult = diagnosticResultRepo.findByExternalOrderIdAndDeletedFalse(order.getExternalOrderId()); + // A poll that brings nothing new must not rewrite the rows: every rewrite resets processed + // (so MMU re-uploads the order) and would re-send it to every tablet. + boolean resultUnchanged = existingResult.isPresent() && sameResult(existingResult.get(), pollResult); + boolean orderUnchanged = sameOrderStatus(order, pollResult); DiagnosticResult result = existingResult.orElseGet(DiagnosticResult::new); + if (resultUnchanged && orderUnchanged && !writeBackWhenClosed) { + ingestAssets(order, pollResult); + diagnosticOrderRepo.recordUnchangedPoll(order.getId(), new Timestamp(System.currentTimeMillis()), + order.getRetryCount()); + DiagnosticOrderResultDto unchanged = new DiagnosticOrderResultDto(); + unchanged.setExternalOrderId(order.getExternalOrderId()); + unchanged.setOrderType(order.getOrderType()); + unchanged.setStatus(order.getStatus()); + unchanged.setProviderStatus(result.getProviderStatus()); + unchanged.setResultSummary(result.getResultSummary()); + unchanged.setErrorMessage(order.getErrorMessage()); + unchanged.setReasonToClose(order.getReasonToClose()); + unchanged.setTbPresence(result.getTbPresence()); + unchanged.setTbConfidence(result.getTbConfidence()); + unchanged.setDrugResistancePresence(result.getDrugResistancePresence()); + return unchanged; + } result.setExternalOrderId(order.getExternalOrderId()); result.setBeneficiaryId(order.getBeneficiaryId()); result.setProviderStatus(pollResult.getStatus().name()); @@ -239,7 +489,8 @@ public DiagnosticOrderResultDto processResult(DiagnosticOrder order, DiagnosticP result.setTbPresence(pollResult.getTbPresence()); result.setTbConfidence(pollResult.getTbConfidence()); result.setDrugResistancePresence(pollResult.getDrugResistancePresence()); - result.setCreatedBy("SYSTEM"); + result.setCreatedBy(actingUser); + result.setModifiedBy(actingUser); if (result.getVanID() == null) { // Inherit from the parent order rather than re-reading Redis — the result belongs // to whichever van originated the order, not whichever van happens to be polling now. @@ -250,6 +501,9 @@ public DiagnosticOrderResultDto processResult(DiagnosticOrder order, DiagnosticP diagnosticResultRepo.save(result); if (result.getVanSerialNo() == null) diagnosticResultRepo.updateVanSerialNo(result.getId()); } catch (DataIntegrityViolationException dive) { + // Only a first insert can lose a race (unique external_order_id). Any other integrity + // failure means the result was not saved, so the order must not move on without it. + if (existingResult.isPresent()) throw dive; logger.warn("Lost result upsert race for externalOrderId={}", order.getExternalOrderId()); result = diagnosticResultRepo.findByExternalOrderIdAndDeletedFalse(order.getExternalOrderId()).orElse(result); } @@ -262,9 +516,12 @@ public DiagnosticOrderResultDto processResult(DiagnosticOrder order, DiagnosticP order.setProviderOrderId(pollResult.getProviderOrderId()); } order.setLastPolledAt(new Timestamp(System.currentTimeMillis())); + order.setModifiedBy(actingUser); + order.setProcessed("N"); diagnosticOrderRepo.save(order); - if (DiagnosticOrderStatus.COMPLETED.name().equals(order.getStatus())) { + if (DiagnosticOrderStatus.COMPLETED.name().equals(order.getStatus()) + || (writeBackWhenClosed && DiagnosticOrderStatus.CLOSED.name().equals(order.getStatus()))) { recordTbSuspectedResult(order, result); } @@ -273,7 +530,7 @@ public DiagnosticOrderResultDto processResult(DiagnosticOrder order, DiagnosticP dto.setOrderType(order.getOrderType()); dto.setStatus(order.getStatus()); dto.setErrorMessage(order.getErrorMessage()); - dto.setReasonForRefusal(order.getReasonToClose()); + dto.setReasonToClose(order.getReasonToClose()); dto.setProviderStatus(result.getProviderStatus()); dto.setResultSummary(result.getResultSummary()); dto.setTbPresence(result.getTbPresence()); @@ -329,8 +586,90 @@ private void ingestAssets(DiagnosticOrder order, DiagnosticPollResult pollResult } } + // The scheduler loads its due-for-poll batch at the start of a tick and polls each order in turn, so + // by the time an order's turn comes it may have been completed/closed by a manual entry. Polling and + // saving that stale copy would overwrite the manual result (whole-row save, no @Version), so the + // order is re-read under the beneficiary lock and skipped unless it is still awaiting a result. + // Failures are recorded on that same fresh row, inside the lock, for the same reason. @Override public DiagnosticPollResult pollOnce(DiagnosticOrder order) throws Exception { + Optional polled = withBeneficiaryLockIfFree(order.getBeneficiaryId(), () -> { + Optional current = findOutstandingOrder(order.getId()); + if (current.isEmpty()) { + logger.info("Skipping poll for orderId={}: no longer PENDING/IN_PROGRESS", order.getId()); + return null; + } + DiagnosticOrder fresh = current.get(); + try { + return pollOnceLocked(fresh); + } catch (Exception e) { + int retries = (fresh.getRetryCount() == null ? 0 : fresh.getRetryCount()) + 1; + if (java.util.Objects.equals(fresh.getErrorMessage(), e.getMessage())) { + // Same failure as last time: only the attempt is recorded (see recordUnchangedPoll). + diagnosticOrderRepo.recordUnchangedPoll(fresh.getId(), new Timestamp(System.currentTimeMillis()), retries); + } else { + fresh.setRetryCount(retries); + fresh.setLastPolledAt(new Timestamp(System.currentTimeMillis())); + fresh.setErrorMessage(e.getMessage()); + fresh.setModifiedBy("SYSTEM"); + fresh.setProcessed("N"); + diagnosticOrderRepo.save(fresh); + } + throw e; + } + }); + if (polled.isEmpty()) { + logger.debug("Poll for orderId={} skipped or deferred (beneficiary busy / order resolved)", order.getId()); + } + return polled.orElse(null); + } + + // Same stale-copy problem as pollOnce: the daily expiry batch is loaded up front, so each order is + // re-read under the lock and only closed if it is still outstanding. + @Override + public void expireOrder(DiagnosticOrder order, String reason) throws Exception { + withBeneficiaryLock(order.getBeneficiaryId(), () -> { + Optional current = findOutstandingOrder(order.getId()); + if (current.isEmpty()) { + logger.info("Skipping expiry for orderId={}: no longer PENDING/IN_PROGRESS", order.getId()); + return null; + } + DiagnosticOrder fresh = current.get(); + fresh.setStatus(DiagnosticOrderStatus.CLOSED.name()); + fresh.setReasonToClose(reason); + fresh.setLastPolledAt(new Timestamp(System.currentTimeMillis())); + fresh.setModifiedBy("SYSTEM"); + fresh.setProcessed("N"); + diagnosticOrderRepo.save(fresh); + notifyProviderOrderClosed(fresh, reason); + return null; + }); + } + + private static boolean sameResult(DiagnosticResult stored, DiagnosticPollResult polled) { + return java.util.Objects.equals(stored.getProviderStatus(), polled.getStatus() == null ? null : polled.getStatus().name()) + && java.util.Objects.equals(stored.getResultSummary(), polled.getResultSummary()) + && java.util.Objects.equals(stored.getTbPresence(), polled.getTbPresence()) + && java.util.Objects.equals(stored.getTbConfidence(), polled.getTbConfidence()) + && java.util.Objects.equals(stored.getDrugResistancePresence(), polled.getDrugResistancePresence()) + && (polled.getAssets() == null || polled.getAssets().isEmpty()); + } + + private static boolean sameOrderStatus(DiagnosticOrder order, DiagnosticPollResult polled) { + return polled.getStatus() != null + && polled.getStatus().name().equals(order.getStatus()) + && java.util.Objects.equals(order.getErrorMessage(), polled.getErrorMessage()) + && (polled.getProviderOrderId() == null + || polled.getProviderOrderId().equals(order.getProviderOrderId())); + } + + private Optional findOutstandingOrder(Long orderId) { + return diagnosticOrderRepo.findById(orderId) + .filter(o -> !Boolean.TRUE.equals(o.getDeleted())) + .filter(o -> OUTSTANDING_STATUSES.contains(o.getStatus())); + } + + private DiagnosticPollResult pollOnceLocked(DiagnosticOrder order) throws Exception { // A null pushResponseJson means the order was never actually confirmed as pushed to the // vendor (e.g. a stale/legacy row) — polling the vendor for it would be meaningless, so // fail it outright instead of burning a vendor call every tick. @@ -338,15 +677,24 @@ public DiagnosticPollResult pollOnce(DiagnosticOrder order) throws Exception { order.setStatus(DiagnosticOrderStatus.FAILED.name()); order.setErrorMessage("No push response recorded for this order — cannot poll"); order.setLastPolledAt(new Timestamp(System.currentTimeMillis())); + order.setModifiedBy("SYSTEM"); + order.setProcessed("N"); diagnosticOrderRepo.save(order); return null; } DiagnosticProvider provider = providerFactory.getProvider(order.getProviderCode()); DiagnosticPollResult result = provider.pollResult(order, false); if (DiagnosticOrderStatus.COMPLETED.equals(result.getStatus())) { - // Save as COMPLETED now, without assets, so a failure fetching/ingesting assets below - // doesn't also lose the already-confirmed completed status (see pollSingle's catch). - processResult(order, result); + // Save as COMPLETED (or CLOSED for an invalid outcome) now, without assets, so a failure + // fetching/ingesting assets below doesn't also lose the already-confirmed status (see + // pollSingle's catch). + boolean invalid = closeIfInvalidPolledResult(order, result); + processResult(order, result, invalid, "SYSTEM"); + if (invalid) { + // Before the asset fetch below: if that throws, this CLOSED order is never polled + // again, so the retest must already exist by then. + pushRetestOrder(order); + } result = provider.pollResult(order, true); // Only ingest the documents this time — the result/order fields were already saved above // and this second, asset-bearing response carries the same status/summary, so re-saving @@ -373,29 +721,51 @@ private DiagnosticOrder resolveOrder(Long beneficiaryId, String orderType, Long return findLatestOrder(beneficiaryId, orderType); } DiagnosticOrderType type = DiagnosticOrderType.fromCode(orderType); - return diagnosticOrderRepo.findByBeneficiaryIdAndVisitCodeAndOrderType(beneficiaryId, visitCode, type.name()) + return diagnosticOrderRepo.findFirstByBeneficiaryIdAndVisitCodeAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, visitCode, type.name()) .orElseThrow(() -> new Exception("DiagnosticOrder not found for beneficiaryId=" + beneficiaryId + ", visitCode=" + visitCode + ", orderType=" + orderType)); } @Override public DiagnosticOrderResultDto triggerManualPoll(Long beneficiaryId, String orderType, Long visitCode) throws Exception { - DiagnosticOrder order = resolveOrder(beneficiaryId, orderType, visitCode); - DiagnosticProvider provider = providerFactory.getProvider(order.getProviderCode()); - DiagnosticPollResult pollResult = provider.pollResult(order, true); - return processResult(order, pollResult); + // Locked, and the order read inside the lock, so this can't interleave with a manual entry or a + // scheduler poll for the same beneficiary and save over what they just wrote. + return withBeneficiaryLock(beneficiaryId, () -> { + DiagnosticOrder order = resolveOrder(beneficiaryId, orderType, visitCode); + if (DiagnosticOrderStatus.MANUAL_ENTRY.name().equals(order.getStatus())) { + throw new IllegalStateException("Cannot poll a MANUAL_ENTRY order — no vendor is involved, " + + "submit the result via manualResult instead"); + } + if (order.getManuallyEnteredBy() != null) { + throw new IllegalStateException("Cannot poll this order: its result was entered manually by " + + order.getManuallyEnteredBy() + " and a vendor poll would overwrite it"); + } + DiagnosticProvider provider = providerFactory.getProvider(order.getProviderCode()); + DiagnosticPollResult pollResult = provider.pollResult(order, true); + boolean invalid = closeIfInvalidPolledResult(order, pollResult); + return processResult(order, pollResult, invalid, "SYSTEM"); + }); } @Override public DiagnosticOrder retryPoll(Long beneficiaryId, String orderType, Long visitCode) throws Exception { + // Locked so the terminal-status check and the reset to PENDING can't straddle a manual entry + // that completes the order in between (which would reopen it for polling). + return withBeneficiaryLock(beneficiaryId, () -> retryPollLocked(beneficiaryId, orderType, visitCode)); + } + + private DiagnosticOrder retryPollLocked(Long beneficiaryId, String orderType, Long visitCode) throws Exception { DiagnosticOrder order = resolveOrder(beneficiaryId, orderType, visitCode); String status = order.getStatus(); if (DiagnosticOrderStatus.COMPLETED.name().equals(status) - || DiagnosticOrderStatus.CANCELLED.name().equals(status) - || DiagnosticOrderStatus.REFUSED.name().equals(status) - || DiagnosticOrderStatus.MANUAL_ENTRY.name().equals(status)) { - throw new IllegalStateException("Cannot retry polling for order in terminal status " + status); + || DiagnosticOrderStatus.CLOSED.name().equals(status)) { + throw new IllegalStateException("Cannot retry polling for order in terminal status " + status + + " — create a new order instead"); + } + if (DiagnosticOrderStatus.MANUAL_ENTRY.name().equals(status)) { + throw new IllegalStateException("Cannot retry polling for a MANUAL_ENTRY order — no vendor is involved, " + + "submit the result via manualResult instead"); } // retriedAt is kept as an audit timestamp only — the scheduler no longer uses it to anchor a @@ -404,6 +774,7 @@ public DiagnosticOrder retryPoll(Long beneficiaryId, String orderType, Long visi order.setRetriedAt(new Timestamp(System.currentTimeMillis())); order.setStatus(DiagnosticOrderStatus.PENDING.name()); order.setErrorMessage(null); + order.setProcessed("N"); return diagnosticOrderRepo.save(order); } @@ -419,22 +790,18 @@ public List getOrdersByBeneficiaryId(Long beneficiaryId) throws @Override public DiagnosticOrderResultDto getOrderResult(Long beneficiaryId, String orderType, Long visitCode) { - DiagnosticOrderResultDto dto = new DiagnosticOrderResultDto(); - dto.setOrderType(orderType); - Optional orderOpt = visitCode != null - ? diagnosticOrderRepo.findByBeneficiaryIdAndVisitCodeAndOrderType(beneficiaryId, visitCode, orderType) + ? diagnosticOrderRepo.findFirstByBeneficiaryIdAndVisitCodeAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, visitCode, orderType) : diagnosticOrderRepo.findFirstByBeneficiaryIdAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc(beneficiaryId, orderType); if (orderOpt.isEmpty()) { + DiagnosticOrderResultDto dto = new DiagnosticOrderResultDto(); + dto.setOrderType(orderType); dto.setStatus("NOT_FOUND"); return dto; } DiagnosticOrder order = orderOpt.get(); - dto.setExternalOrderId(order.getExternalOrderId()); - dto.setStatus(order.getStatus()); - dto.setErrorMessage(order.getErrorMessage()); - dto.setReasonForRefusal(order.getReasonToClose()); + DiagnosticOrderResultDto dto = toResultDto(order); diagnosticResultRepo.findByExternalOrderIdAndDeletedFalse(order.getExternalOrderId()).ifPresent(result -> { dto.setProviderStatus(result.getProviderStatus()); @@ -446,24 +813,75 @@ public DiagnosticOrderResultDto getOrderResult(Long beneficiaryId, String orderT return dto; } + @Override + public java.util.Map> getOrderRecordsByIds(java.util.Collection ids) { + java.util.Map> out = new java.util.LinkedHashMap<>(); + for (DiagnosticOrder order : diagnosticOrderRepo.findAllById(ids)) { + if (Boolean.TRUE.equals(order.getDeleted())) continue; + DiagnosticOrderResultDto dto = toResultDto(order); + if (order.getExternalOrderId() != null) { + diagnosticResultRepo.findByExternalOrderIdAndDeletedFalse(order.getExternalOrderId()).ifPresent(result -> { + dto.setProviderStatus(result.getProviderStatus()); + dto.setResultSummary(result.getResultSummary()); + dto.setTbPresence(result.getTbPresence()); + dto.setTbConfidence(result.getTbConfidence()); + dto.setDrugResistancePresence(result.getDrugResistancePresence()); + }); + } + java.util.Map m = new java.util.LinkedHashMap<>(); + m.put("id", order.getId()); + m.put("beneficiaryId", order.getBeneficiaryId()); + m.put("visitCode", order.getVisitCode()); + m.put("createdDate", order.getCreatedDate()); + m.put("externalOrderId", dto.getExternalOrderId()); + m.put("orderType", dto.getOrderType()); + m.put("status", dto.getStatus()); + m.put("providerStatus", dto.getProviderStatus()); + m.put("resultSummary", dto.getResultSummary()); + m.put("errorMessage", dto.getErrorMessage()); + m.put("reasonToClose", dto.getReasonToClose()); + m.put("tbPresence", dto.getTbPresence()); + m.put("tbConfidence", dto.getTbConfidence()); + m.put("drugResistancePresence", dto.getDrugResistancePresence()); + out.put(order.getId(), m); + } + return out; + } + + private DiagnosticOrderResultDto toResultDto(DiagnosticOrder order) { + DiagnosticOrderResultDto dto = new DiagnosticOrderResultDto(); + dto.setExternalOrderId(order.getExternalOrderId()); + dto.setOrderType(order.getOrderType()); + dto.setStatus(order.getStatus()); + dto.setErrorMessage(order.getErrorMessage()); + dto.setReasonToClose(order.getReasonToClose()); + return dto; + } + @Override public DiagnosticOrderStatusSummaryDto getOrderStatusSummary(String orderType, Integer villageId, - Integer providerServiceMapId) { + Integer providerServiceMapId) { DiagnosticOrderType type = DiagnosticOrderType.fromCode(orderType); - List awaitingProviderResult = diagnosticOrderRepo - .findBeneficiaryIdsAwaitingProviderResult(type.name(), villageId, providerServiceMapId); - List completed = diagnosticOrderRepo - .findBeneficiaryIdsCompleted(type.name(), villageId, providerServiceMapId); - List pollingTimedOut = diagnosticOrderRepo - .findBeneficiaryIdsPollingTimedOut(type.name(), villageId, providerServiceMapId); - List failed = diagnosticOrderRepo - .findBeneficiaryIdsFailed(type.name(), villageId, providerServiceMapId); - List refused = diagnosticOrderRepo - .findBeneficiaryIdsRefused(type.name(), villageId, providerServiceMapId); - List awaitingManualEntry = diagnosticOrderRepo - .findBeneficiaryIdsAwaitingManualEntry(type.name(), villageId, providerServiceMapId); - return new DiagnosticOrderStatusSummaryDto(awaitingProviderResult, completed, pollingTimedOut, failed, refused, - awaitingManualEntry); + List awaitingProviderResult = new ArrayList<>(); + List completed = new ArrayList<>(); + List failed = new ArrayList<>(); + List closed = new ArrayList<>(); + List awaitingManualEntry = new ArrayList<>(); + // One query instead of one per bucket; buckets are the same status groups the per-bucket + // queries used (matched case-insensitively, like the database comparison was). + for (Object[] row : diagnosticOrderRepo.findLatestOrderStatusByBeneficiary(type.name(), villageId, providerServiceMapId)) { + Long beneficiaryId = row[0] != null ? ((Number) row[0]).longValue() : null; + String status = row[1] != null ? row[1].toString().toUpperCase(java.util.Locale.ROOT) : ""; + switch (status) { + case "PENDING", "IN_PROGRESS" -> awaitingProviderResult.add(beneficiaryId); + case "COMPLETED" -> completed.add(beneficiaryId); + case "FAILED" -> failed.add(beneficiaryId); + case "CLOSED", "CANCELLED", "EXPIRED", "REFUSED" -> closed.add(beneficiaryId); + case "MANUAL_ENTRY" -> awaitingManualEntry.add(beneficiaryId); + default -> { } + } + } + return new DiagnosticOrderStatusSummaryDto(awaitingProviderResult, completed, failed, closed, awaitingManualEntry); } @Override @@ -484,14 +902,128 @@ public VendorHealthDto checkVendorHealth(String orderType) throws Exception { } @Override - public DiagnosticOrderResultDto submitManualResult(ManualDiagnosticResultRequestDto request) throws Exception { + public DiagnosticOrderResultDto submitManualResult(ManualDiagnosticResultRequestDto request, String jwtToken) + throws Exception { + boolean hasResult = request.getResultSummary() != null && !request.getResultSummary().isBlank(); + boolean hasReasonToClose = request.getReasonToClose() != null && !request.getReasonToClose().isBlank(); + if (hasResult == hasReasonToClose) { + throw new IllegalArgumentException("Exactly one of resultSummary or reasonToClose must be provided"); + } + + String actingUserName = resolveActingUserName(jwtToken); + + if (hasReasonToClose) { + DiagnosticOrderType orderType = DiagnosticOrderType.fromCode(request.getOrderType()); + DiagnosticOrder closed = closeOrderManually(request.getBeneficiaryId(), orderType, + request.getReasonToClose(), actingUserName); + return toResultDto(closed); + } + + return withBeneficiaryLock(request.getBeneficiaryId(), + () -> submitManualResultLocked(request, actingUserName)); + } + + private DiagnosticOrderResultDto submitManualResultLocked(ManualDiagnosticResultRequestDto request, + String actingUserName) throws Exception { DiagnosticOrder order = findLatestOrder(request.getBeneficiaryId(), request.getOrderType()); if (DiagnosticOrderStatus.COMPLETED.name().equals(order.getStatus())) { throw new IllegalStateException("Cannot submit manual result: order is already COMPLETED (beneficiaryId=" + request.getBeneficiaryId() + ", orderType=" + request.getOrderType() + ")"); } + order.setManuallyEnteredBy(actingUserName); + // An invalid test outcome is still recorded exactly like a normal result (result row + + // tb_suspected write-back), but the order is CLOSED rather than COMPLETED. + DiagnosticOrderStatus status = isInvalidResult(order.getOrderType(), request.getResultSummary(), + SPUTUM_INVALID_MANUAL_RESULT) + ? DiagnosticOrderStatus.CLOSED + : DiagnosticOrderStatus.COMPLETED; DiagnosticPollResult pollResult = new DiagnosticPollResult( - DiagnosticOrderStatus.COMPLETED, null, request.getResultSummary(), null, null, null, null, null, null); - return processResult(order, pollResult); + status, null, request.getResultSummary(), null, null, null, null, null, null); + return processResult(order, pollResult, true, actingUserName); + } + + // sputumInvalidResult differs by source: SPUTUM_INVALID_POLLED_RESULT for vendor polls, + // SPUTUM_INVALID_MANUAL_RESULT for manual entry. The X-ray value is the same for both. + private static boolean isInvalidResult(String orderTypeCode, String resultSummary, String sputumInvalidResult) { + if (resultSummary == null) { + return false; + } + String summary = resultSummary.trim(); + DiagnosticOrderType type = DiagnosticOrderType.fromCode(orderTypeCode); + if (type == DiagnosticOrderType.XRAY_CHEST) { + return XRAY_INVALID_RESULT.equalsIgnoreCase(summary); + } + if (type == DiagnosticOrderType.MTB || type == DiagnosticOrderType.MDR_RIF) { + return sputumInvalidResult.equalsIgnoreCase(summary); + } + return false; + } + + // Automatic retest after a polled invalid outcome: a brand new PENDING row copying the closed + // order's beneficiary, visit, vendor and patient details, with only a fresh externalOrderId, + // pushed to the vendor straight away. Never throws — a failure here must not undo the close. + private void pushRetestOrder(DiagnosticOrder closed) { + try { + withBeneficiaryLockBlocking(closed.getBeneficiaryId(), () -> { + pushRetestOrderLocked(closed); + return null; + }); + } catch (Exception e) { + logger.error("Failed to create retest order after invalid result, closedOrderId={}: {}", + closed.getId(), e.getMessage()); + } + } + + private void pushRetestOrderLocked(DiagnosticOrder closed) { + // A user push may have created a fresh order for this beneficiary+orderType after this one was + // closed — the retest would then put the same patient on the vendor twice, so skip it. + Optional latest = diagnosticOrderRepo + .findFirstByBeneficiaryIdAndOrderTypeAndDeletedFalseOrderByCreatedDateDesc( + closed.getBeneficiaryId(), closed.getOrderType()); + if (latest.isPresent() && !latest.get().getId().equals(closed.getId()) + && BLOCKING_STATUSES.contains(latest.get().getStatus())) { + logger.info("Retest skipped for closedOrderId={}: newer order id={} (status={}) already exists", + closed.getId(), latest.get().getId(), latest.get().getStatus()); + return; + } + try { + DiagnosticOrder retest = new DiagnosticOrder(); + retest.setVanID(closed.getVanID()); + retest.setParkingPlaceID(closed.getParkingPlaceID()); + retest.setOrderEvent(closed.getOrderEvent()); + retest.setBeneficiaryId(closed.getBeneficiaryId()); + retest.setVisitCode(closed.getVisitCode()); + retest.setProviderServiceName(closed.getProviderServiceName()); + retest.setProviderCode(closed.getProviderCode()); + retest.setOrderType(closed.getOrderType()); + retest.setExternalOrderId(String.format("%s-%d-%s", UUID.randomUUID(), closed.getVisitCode(), + closed.getOrderType())); + retest.setStatus(DiagnosticOrderStatus.PENDING.name()); + retest.setPatientFirstName(closed.getPatientFirstName()); + retest.setPatientLastName(closed.getPatientLastName()); + retest.setPatientDateOfBirth(closed.getPatientDateOfBirth()); + retest.setPatientSex(closed.getPatientSex()); + retest.setCreatedBy("SYSTEM"); + retest.setModifiedBy("SYSTEM"); + retest = diagnosticOrderRepo.save(retest); + retest = pushToProvider(retest, closed.getProviderCode()); + logger.info("Retest order created after invalid result: closedOrderId={}, retestOrderId={}, " + + "externalOrderId={}, status={}", closed.getId(), retest.getId(), retest.getExternalOrderId(), + retest.getStatus()); + } catch (Exception e) { + logger.error("Failed to create retest order after invalid result, closedOrderId={}: {}", + closed.getId(), e.getMessage()); + } + } + + // A vendor poll that COMPLETED with an invalid outcome is downgraded to CLOSED in place. + // Returns true when that happened, so the caller still writes the result back to tb_suspected. + private static boolean closeIfInvalidPolledResult(DiagnosticOrder order, DiagnosticPollResult result) { + if (DiagnosticOrderStatus.COMPLETED.equals(result.getStatus()) + && isInvalidResult(order.getOrderType(), result.getResultSummary(), SPUTUM_INVALID_POLLED_RESULT)) { + result.setStatus(DiagnosticOrderStatus.CLOSED); + return true; + } + return false; } } diff --git a/src/main/java/com/iemr/flw/service/impl/DiagnosticPollSchedulerService.java b/src/main/java/com/iemr/flw/service/impl/DiagnosticPollSchedulerService.java index b21c7095c..1a36e8cd0 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiagnosticPollSchedulerService.java +++ b/src/main/java/com/iemr/flw/service/impl/DiagnosticPollSchedulerService.java @@ -2,7 +2,6 @@ import com.iemr.flw.domain.iemr.DiagnosticOrder; import com.iemr.flw.integration.provider.DiagnosticProviderFactory; -import com.iemr.flw.masterEnum.DiagnosticOrderStatus; import com.iemr.flw.masterEnum.DiagnosticOrderType; import com.iemr.flw.repo.iemr.DiagnosticOrderRepo; import com.iemr.flw.service.DiagnosticOrderService; @@ -11,16 +10,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import org.springframework.web.client.ResourceAccessException; import java.sql.Timestamp; +import java.time.LocalDate; import java.util.List; +import java.util.function.Supplier; -// Every due order (status PENDING/IN_PROGRESS) is polled on every tick from the moment it's created — -// there is no per-order initial delay or rolling give-up window anymore. A tick is skipped entirely -// for an order-type family if diagnostic.provider.xray / diagnostic.provider.truenat has no active -// vendor configured right now (checked live via DiagnosticProviderFactory, not any value stored on the -// order row). Once a day, expireOutstandingOrders sweeps up everything still PENDING/IN_PROGRESS (for -// order-type families that do have an active vendor) and marks it EXPIRED. @Service public class DiagnosticPollSchedulerService { @@ -37,50 +33,70 @@ public class DiagnosticPollSchedulerService { @Scheduled(fixedDelayString = "${diagnostic.poll.xray.tick-ms:15000}") public void pollXrayOrders() { - if (noActiveVendor(DiagnosticOrderType.XRAY_CHEST)) { - logger.debug("No active vendor configured for XRAY_CHEST — skipping poll tick"); - return; - } - List candidates = diagnosticOrderRepo.findXrayDueForPoll(); - logger.info("XRAY poll tick: {} order(s) in due-for-poll queue", candidates.size()); - if (candidates.isEmpty()) return; - - for (DiagnosticOrder order : candidates) { - pollSingle(order); - } - logger.info("Polled {} pending XRAY diagnostic orders", candidates.size()); + pollDueOrders("XRAY", DiagnosticOrderType.XRAY_CHEST, + diagnosticOrderRepo::findXrayDueForPoll); } @Scheduled(fixedDelayString = "${diagnostic.poll.truenat.tick-ms:60000}") public void pollTrueNatOrders() { - if (noActiveVendor(DiagnosticOrderType.MTB)) { - logger.debug("No active vendor configured for TrueNat — skipping poll tick"); + pollDueOrders("TrueNat", DiagnosticOrderType.MTB, + diagnosticOrderRepo::findTrueNatDueForPoll); + } + + private void pollDueOrders(String label, DiagnosticOrderType orderType, Supplier> dueOrders) { + String providerCode = providerFactory.getProviderCodeForOrderType(orderType); + if (providerCode == null || providerCode.isBlank()) { + logger.debug("No active vendor configured for {} — skipping poll tick", label); return; } - List candidates = diagnosticOrderRepo.findTrueNatDueForPoll(); - logger.info("TrueNat poll tick: {} order(s) in due-for-poll queue", candidates.size()); + List candidates = dueOrders.get(); + logger.info("{} poll tick: {} order(s) in due-for-poll queue", label, candidates.size()); if (candidates.isEmpty()) return; - for (DiagnosticOrder order : candidates) { - pollSingle(order); + if (!providerFactory.getProvider(providerCode).checkHealth(orderType)) { + logger.warn("{} vendor ping failed — skipping poll tick, {} order(s) left for the next tick", + label, candidates.size()); + return; } - logger.info("Polled {} pending TrueNat diagnostic orders", candidates.size()); - } - @Scheduled(cron = "${diagnostic.poll.expiry-cron:0 0 18 * * *}") - public void expireOutstandingOrders() { - List outstanding = diagnosticOrderRepo.findAllOutstandingOrders(); - int expired = 0; - for (DiagnosticOrder order : outstanding) { - if (noActiveVendor(DiagnosticOrderType.fromCode(order.getOrderType()))) { - continue; // awaiting manual entry — not subject to the polling cutoff + int polled = 0; + for (DiagnosticOrder order : candidates) { + polled++; + if (!pollSingle(order)) { + logger.warn("{} vendor unreachable mid-tick — stopping, {} order(s) left for the next tick", + label, candidates.size() - polled); + break; } - expire(order); - expired++; - } - if (expired > 0) { - logger.warn("Daily polling cutoff reached: marked {} outstanding order(s) EXPIRED", expired); } + logger.info("Polled {} of {} pending {} diagnostic orders", polled, candidates.size(), label); + } + + // Auto-closure of outstanding orders at the daily cutoff is disabled for now — orders are no longer + // closed automatically. Uncomment this job (and expire() below) to re-enable it. + // @Scheduled(cron = "${diagnostic.poll.expiry-cron:0 50 23 * * *}") + // public void expireOutstandingOrders() { + // List outstanding = diagnosticOrderRepo.findAllOutstandingOrders(startOfToday(), startOfTomorrow()); + // int expired = 0; + // for (DiagnosticOrder order : outstanding) { + // if (noActiveVendor(DiagnosticOrderType.fromCode(order.getOrderType()))) { + // continue; // awaiting manual entry — not subject to the polling cutoff + // } + // expire(order); + // expired++; + // } + // if (expired > 0) { + // logger.warn("Daily polling cutoff reached: marked {} outstanding order(s) CLOSED", expired); + // } + // } + + // The (disabled) daily close only handles orders created today. JVM default zone on purpose: it's the + // same clock created_date is stamped with (@CreationTimestamp), so the day boundaries line up. + private static Timestamp startOfToday() { + return Timestamp.valueOf(LocalDate.now().atStartOfDay()); + } + + private static Timestamp startOfTomorrow() { + return Timestamp.valueOf(LocalDate.now().plusDays(1).atStartOfDay()); } private boolean noActiveVendor(DiagnosticOrderType orderType) { @@ -88,24 +104,31 @@ private boolean noActiveVendor(DiagnosticOrderType orderType) { return providerCode == null || providerCode.isBlank(); } - private void expire(DiagnosticOrder order) { - order.setStatus(DiagnosticOrderStatus.EXPIRED.name()); - order.setErrorMessage("Daily polling cutoff reached without a result"); - order.setLastPolledAt(new Timestamp(System.currentTimeMillis())); - diagnosticOrderRepo.save(order); - } + // Used only by the (disabled) auto-closure job above. expireOrder re-reads the order under the + // beneficiary lock, so an order completed manually after this batch was loaded is left alone. + // private void expire(DiagnosticOrder order) { + // String reason = "Order validity expired for the day " + LocalDate.now(ZoneId.of("Asia/Kolkata")); + // try { + // diagnosticOrderService.expireOrder(order, reason); + // } catch (Exception e) { + // logger.error("Expiry failed for orderId={}: {}", order.getId(), e.getMessage()); + // } + // } - private void pollSingle(DiagnosticOrder order) { + // Returns false only when the vendor couldn't be reached at all (connect/read timeout, refused + // connection) — the caller stops the tick then. Any other failure is specific to this order + // (bad data, vendor-side rejection), so it's recorded and the tick carries on. + private boolean pollSingle(DiagnosticOrder order) { try { - // pollOnce now saves the result/order fields and ingests any documents itself — - // nothing left to do here on success. diagnosticOrderService.pollOnce(order); + return true; + } catch (ResourceAccessException e) { + logger.error("Vendor unreachable polling orderId={}: {}", order.getId(), e.getMessage()); + return false; } catch (Exception e) { logger.error("Poll failed for orderId={}: {}", order.getId(), e.getMessage()); - order.setRetryCount(order.getRetryCount() + 1); - order.setLastPolledAt(new Timestamp(System.currentTimeMillis())); - order.setErrorMessage(e.getMessage()); - diagnosticOrderRepo.save(order); + return true; } } + } \ No newline at end of file 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 c40b65d7b..1df9a2018 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; @@ -150,7 +151,9 @@ public List getAllForms() { .stream() .map(form -> { try { - return loadLatestFromDb(form.getFormId()); + DynamicFormDTO latest = loadLatestFromDb(form.getFormId()); + latest.setVersions(loadAllVersionsFromDb(form.getFormId())); + return latest; } catch (RuntimeException e) { log.warn("Skipping form {} — no active version: {}", form.getFormId(), e.getMessage()); return null; @@ -211,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()) { @@ -266,6 +273,14 @@ private QuestionValidation buildValidationEntity(QuestionValidationDTO dto, // ── LOAD / READ HELPERS ─────────────────────────────────────────────────── + /** Full definition of every active version of the form, oldest first. */ + private List loadAllVersionsFromDb(Long formId) { + return versionRepo.findByDynamicForm_FormIdOrderByVersionNumberAsc(formId).stream() + .filter(version -> Boolean.TRUE.equals(version.getIsActive())) + .map(version -> buildFormDto(version.getDynamicForm(), version)) + .collect(Collectors.toList()); + } + private DynamicFormDTO loadLatestFromDb(Long formId) { FormVersion version = versionRepo.findByDynamicForm_FormIdAndIsLatest(formId, true) .orElseThrow(() -> new RuntimeException("No active version for formId: " + formId)); @@ -280,7 +295,7 @@ private DynamicFormDTO loadLatestFromDb(Long formId) { private DynamicFormDTO buildFormDto(DynamicForm form, FormVersion version) { // Query 1: sections List sections = sectionRepo - .findByFormVersion_VersionIdOrderByDisplayOrderAsc(version.getVersionId()); + .findByFormVersion_VersionIdAndIsActiveTrueOrderByDisplayOrderAsc(version.getVersionId()); if (sections.isEmpty()) { DynamicFormDTO dto = mapper.toDto(form); dto.setVersionNumber(version.getVersionNumber()); @@ -413,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 new file mode 100644 index 000000000..235093d4f --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormReconciliationServiceImpl.java @@ -0,0 +1,329 @@ +/* + * 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.service.impl; + +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.domain.iemr.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.OptionCondition; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.QuestionValidation; +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.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.mapper.DynamicFormMapper; +import com.iemr.flw.repo.iemr.DynamicFormRepo; +import com.iemr.flw.repo.iemr.FormSectionRepo; +import com.iemr.flw.repo.iemr.FormVersionRepo; +import com.iemr.flw.repo.iemr.OptionConditionRepo; +import com.iemr.flw.repo.iemr.QuestionOptionRepo; +import com.iemr.flw.repo.iemr.QuestionValidationRepo; +import com.iemr.flw.repo.iemr.SectionQuestionRepo; +import com.iemr.flw.service.DynamicFormReconciliationService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.function.IntConsumer; +import java.util.function.Supplier; + +/** + * In-place reconciliation for dynamic form structure — see {@link DynamicFormReconciliationService}. + * Standalone: does not depend on {@link DynamicFormDefinitionServiceImpl}'s private helpers, since + * that service's write path (full version clone) is a deliberately different mechanism from this one. + * + * @author Piramal Swasthya + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class DynamicFormReconciliationServiceImpl implements DynamicFormReconciliationService { + + private final DynamicFormRepo formRepo; + private final FormVersionRepo versionRepo; + private final FormSectionRepo sectionRepo; + private final SectionQuestionRepo questionRepo; + private final QuestionOptionRepo optionRepo; + private final QuestionValidationRepo validationRepo; + private final OptionConditionRepo conditionRepo; + private final DynamicFormMapper mapper; + + // ── Form / Version ──────────────────────────────────────────────────────── + + @Override + @Transactional + public DynamicForm ensureForm(DynamicFormDTO dto) { + Optional existing = formRepo.findByFormUuid(dto.getFormUuid()); + if (existing.isPresent()) { + DynamicForm form = existing.get(); + if (Boolean.FALSE.equals(form.getIsActive())) { + form.setIsActive(true); + form = formRepo.save(form); + log.info("Form '{}' was inactive — reactivated.", dto.getFormUuid()); + } + return form; + } + DynamicForm form = mapper.toEntity(dto); + form.setFormId(null); + return formRepo.save(form); + } + + @Override + @Transactional + public FormVersion ensureLatestVersion(DynamicForm form) { + return versionRepo.findByDynamicForm_FormIdAndIsLatest(form.getFormId(), true) + .orElseGet(() -> { + FormVersion version = new FormVersion(); + version.setDynamicForm(form); + version.setVersionNumber(1); + version.setIsLatest(true); + return versionRepo.save(version); + }); + } + + // ── Section / Question / Option / Validation / Condition ───────────────── + + @Override + @Transactional + public FormSection ensureSection(FormVersion version, FormSectionDTO dto) { + return sectionRepo.findByFormVersion_VersionIdAndSectionUuid(version.getVersionId(), dto.getSectionUuid()) + .orElseGet(() -> createSection(version, dto)); + } + + @Override + @Transactional + public SectionQuestion ensureQuestion(FormSection section, SectionQuestionDTO dto) { + return questionRepo.findByFormSection_SectionIdAndQuestionUuid(section.getSectionId(), dto.getQuestionUuid()) + .orElseGet(() -> createQuestion(section, dto)); + } + + @Override + @Transactional + public QuestionOption ensureOption(SectionQuestion question, QuestionOptionDTO dto) { + return optionRepo.findBySectionQuestion_QuestionIdAndOptionValue(question.getQuestionId(), dto.getOptionValue()) + .orElseGet(() -> createOption(question, dto)); + } + + @Override + @Transactional + public QuestionValidation ensureValidation(SectionQuestion question, QuestionValidationDTO dto) { + return validationRepo.findBySectionQuestion_QuestionIdAndValidationTypeAndValidationParam( + question.getQuestionId(), dto.getValidationType(), dto.getValidationParam()) + .orElseGet(() -> createValidation(question, dto)); + } + + @Override + @Transactional + public OptionCondition ensureCondition(QuestionOption option, OptionConditionDTO dto, FormVersion version) { + Optional existing; + if (dto.getTargetQuestionUuid() != null) { + existing = conditionRepo.findByQuestionOption_OptionIdAndActionTypeAndTargetQuestion_QuestionUuid( + option.getOptionId(), dto.getActionType(), dto.getTargetQuestionUuid()); + } else if (dto.getTargetSectionUuid() != null) { + existing = conditionRepo.findByQuestionOption_OptionIdAndActionTypeAndTargetSection_SectionUuid( + option.getOptionId(), dto.getActionType(), dto.getTargetSectionUuid()); + } else { + existing = Optional.empty(); + } + return existing.orElseGet(() -> createCondition(option, dto, version)); + } + + // ── Update / Remove ──────────────────────────────────────────────────────── + + @Override + @Transactional + public SectionQuestion updateQuestion(Long questionId, SectionQuestionDTO dto) { + SectionQuestion question = questionRepo.findById(questionId) + .orElseThrow(() -> new NoSuchElementException("Question not found: " + questionId)); + question.setQuestionText(dto.getQuestionText()); + question.setQuestionTextHindi(dto.getQuestionTextHindi()); + question.setQuestionType(dto.getQuestionType()); + question.setIsMandatory(dto.getIsMandatory()); + question.setMaxLength(dto.getMaxLength()); + question.setDefaultValue(dto.getDefaultValue()); + question.setContainsPii(dto.getContainsPii()); + if (dto.getDisplayOrder() != null && !dto.getDisplayOrder().equals(question.getDisplayOrder())) { + moveQuestion(question, dto.getDisplayOrder()); + } + return questionRepo.save(question); + } + + @Override + @Transactional + public void unlinkQuestion(Long questionId) { + SectionQuestion question = questionRepo.findById(questionId) + .orElseThrow(() -> new NoSuchElementException("Question not found: " + questionId)); + question.setIsActive(false); + questionRepo.save(question); + } + + @Override + @Transactional + public void removeOption(Long optionId) { + QuestionOption option = optionRepo.findById(optionId) + .orElseThrow(() -> new NoSuchElementException("Option not found: " + optionId)); + option.setIsActive(false); + optionRepo.save(option); + } + + // ── Read-only lookups ────────────────────────────────────────────────────── + + @Override + public Optional latestVersion(String formUuid) { + return formRepo.findByFormUuid(formUuid) + .flatMap(form -> versionRepo.findByDynamicForm_FormIdAndIsLatest(form.getFormId(), true)); + } + + @Override + public Optional section(FormVersion version, String sectionUuid) { + return sectionRepo.findByFormVersion_VersionIdAndSectionUuid(version.getVersionId(), sectionUuid); + } + + @Override + public Optional question(FormSection section, String questionUuid) { + return questionRepo.findByFormSection_SectionIdAndQuestionUuid(section.getSectionId(), questionUuid); + } + + @Override + public Optional option(SectionQuestion question, String optionValue) { + return optionRepo.findBySectionQuestion_QuestionIdAndOptionValue(question.getQuestionId(), optionValue); + } + + // ── Create helpers ───────────────────────────────────────────────────────── + + private FormSection createSection(FormVersion version, FormSectionDTO dto) { + int order = resolveOrder(dto.getDisplayOrder(), + () -> sectionRepo.findTopByFormVersion_VersionIdOrderByDisplayOrderDesc(version.getVersionId()) + .map(FormSection::getDisplayOrder), + from -> sectionRepo.shiftDisplayOrder(version.getVersionId(), from, Integer.MAX_VALUE, 1)); + FormSection section = mapper.toEntity(dto); + section.setSectionId(null); + section.setFormVersion(version); + section.setDisplayOrder(order); + section.setQuestions(new ArrayList<>()); + return sectionRepo.save(section); + } + + private SectionQuestion createQuestion(FormSection section, SectionQuestionDTO dto) { + int order = resolveOrder(dto.getDisplayOrder(), + () -> questionRepo.findTopByFormSection_SectionIdOrderByDisplayOrderDesc(section.getSectionId()) + .map(SectionQuestion::getDisplayOrder), + from -> questionRepo.shiftDisplayOrder(section.getSectionId(), from, Integer.MAX_VALUE, 1)); + SectionQuestion question = mapper.toEntity(dto); + question.setQuestionId(null); + question.setFormSection(section); + question.setDisplayOrder(order); + question.setOptions(new ArrayList<>()); + question.setValidations(new ArrayList<>()); + return questionRepo.save(question); + } + + private QuestionOption createOption(SectionQuestion question, QuestionOptionDTO dto) { + int order = resolveOrder(dto.getDisplayOrder(), + () -> optionRepo.findTopBySectionQuestion_QuestionIdOrderByDisplayOrderDesc(question.getQuestionId()) + .map(QuestionOption::getDisplayOrder), + from -> optionRepo.shiftDisplayOrder(question.getQuestionId(), from, Integer.MAX_VALUE, 1)); + 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); + } + + private QuestionValidation createValidation(SectionQuestion question, QuestionValidationDTO dto) { + QuestionValidation validation = mapper.toEntity(dto); + validation.setValidationId(null); + validation.setSectionQuestion(question); + return validationRepo.save(validation); + } + + private OptionCondition createCondition(QuestionOption option, OptionConditionDTO dto, FormVersion version) { + OptionCondition condition = mapper.toEntity(dto); + condition.setConditionId(null); + condition.setQuestionOption(option); + + if (dto.getTargetQuestionUuid() != null) { + condition.setTargetQuestion(questionRepo + .findByFormSection_FormVersion_VersionIdAndQuestionUuid(version.getVersionId(), dto.getTargetQuestionUuid()) + .orElseThrow(() -> new NoSuchElementException( + "targetQuestionUuid not found in this form version: " + dto.getTargetQuestionUuid()))); + } else if (dto.getTargetQuestionId() != null) { + condition.setTargetQuestion(questionRepo.findById(dto.getTargetQuestionId()) + .orElseThrow(() -> new NoSuchElementException("Question not found: " + dto.getTargetQuestionId()))); + } + + if (dto.getTargetSectionUuid() != null) { + condition.setTargetSection(sectionRepo + .findByFormVersion_VersionIdAndSectionUuid(version.getVersionId(), dto.getTargetSectionUuid()) + .orElseThrow(() -> new NoSuchElementException( + "targetSectionUuid not found in this form version: " + dto.getTargetSectionUuid()))); + } else if (dto.getTargetSectionId() != null) { + condition.setTargetSection(sectionRepo.findById(dto.getTargetSectionId()) + .orElseThrow(() -> new NoSuchElementException("Section not found: " + dto.getTargetSectionId()))); + } + + return conditionRepo.save(condition); + } + + /** + * Omitted displayOrder → append after the current max sibling (no shift needed). + * Explicit displayOrder → push every sibling at or after that position up by one, then use it as-is. + */ + private int resolveOrder(Integer requested, Supplier> currentMaxSupplier, + IntConsumer shiftFromInclusive) { + if (requested == null) { + return currentMaxSupplier.get().orElse(0) + 1; + } + shiftFromInclusive.accept(requested); + return requested; + } + + /** + * Moves a question already at oldPos to newPos within its section, shifting the siblings in + * between to keep displayOrder contiguous — same three-branch logic a full reorder needs + * regardless of direction. + */ + private void moveQuestion(SectionQuestion question, int newPos) { + int oldPos = question.getDisplayOrder(); + Long sectionId = question.getFormSection().getSectionId(); + if (newPos < oldPos) { + questionRepo.shiftDisplayOrder(sectionId, newPos, oldPos - 1, 1); + } else { + questionRepo.shiftDisplayOrder(sectionId, oldPos + 1, newPos, -1); + } + question.setDisplayOrder(newPos); + } +} 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 e163959ce..b14ab50c1 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java @@ -61,9 +61,12 @@ import java.sql.Timestamp; import java.time.LocalDate; import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; 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 +139,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 +167,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 +260,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 +319,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); @@ -442,6 +462,24 @@ private QuestionOption resolveOption( // ---- read helpers ---- + @Override + public Map getResponsesByIds(Collection responseIds) { + List responses = formResponseRepo.findAllById(responseIds); + 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)); + Map out = new LinkedHashMap<>(); + for (FormResponse r : responses) { + FormResponseDTO dto = buildFormResponseDTO(r, loadSectionResponseDTOs(r.getResponseId())); + dto.setVersionNumber(versionNumberById.get(r.getVersionId())); + out.put(r.getResponseId(), dto); + } + return out; + } + private List loadSectionResponseDTOs(Long responseId) { List sections = sectionResponseRepo.findByResponseId(responseId); if (sections.isEmpty()) { @@ -461,11 +499,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 +542,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 f03398c5a..9a6e04877 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()); diff --git a/src/main/java/com/iemr/flw/service/impl/StopTBServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/StopTBServiceImpl.java index cdeaf11af..3c00b1973 100644 --- a/src/main/java/com/iemr/flw/service/impl/StopTBServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/StopTBServiceImpl.java @@ -30,6 +30,7 @@ import com.iemr.flw.repo.iemr.StopTBGeneralOpdRepo; import com.iemr.flw.repo.iemr.TBScreeningRepo; import com.iemr.flw.service.CampConfigService; +import com.iemr.flw.service.StopTBPrescriptionService; import com.iemr.flw.service.StopTBService; import com.iemr.flw.service.TBStopVisitService; import org.slf4j.Logger; @@ -51,6 +52,9 @@ public class StopTBServiceImpl implements StopTBService { @Autowired private CampConfigService campConfigService; + @Autowired + private StopTBPrescriptionService stopTBPrescriptionService; + @Autowired private BenFlowStatusRepo benFlowStatusRepo; @@ -254,6 +258,13 @@ public List> saveNurseTBScreening(List> screening.setKeyPopulationRiskFactors(toJsonString(data.get("keyPopulationRiskFactors"))); screening.setHivStatusId(getInt(data, "hivStatusId")); screening.setHivStatus(getString(data, "hivStatus")); + screening.setChestPain(getBool(data, "chestPain")); + screening.setShortnessOfBreath(getBool(data, "shortnessOfBreath")); + screening.setFatigue(getBool(data, "fatigue")); + screening.setFailureToGainWeight(getBool(data, "failureToGainWeightInChildren")); + screening.setDecreasedActivityOrPlayfulness(getBool(data, "decreasedActivityOrPlayfulnessInChildren")); + screening.setOthers(getBool(data, "otherSymptoms")); + String symptomaticInput = getString(data, "symptomatic"); if ("Yes".equalsIgnoreCase(symptomaticInput)) { screening.setSympotomatic(null); @@ -349,23 +360,59 @@ private Map screeningToMap(TBScreening s) { m.put("visitDate", s.getVisitDate()); m.put("updateDate", s.getLastModDate()); m.put("updatedBy", s.getModifiedBy()); + m.put("chestPain", s.getChestPain()); + m.put("shortnessOfBreath", s.getShortnessOfBreath()); + m.put("fatigue", s.getFatigue()); + m.put("failureToGainWeightInChildren", s.getFailureToGainWeight()); + m.put("decreasedActivityOrPlayfulnessInChildren", s.getDecreasedActivityOrPlayfulness()); + m.put("otherSymptoms", s.getOthers()); return m; } // ── Nurse: General OPD ──────────────────────────────────────────────────── + // Whole list is one transaction: any failure (incl. insufficient stock) rolls back every record. @Override - @Transactional + @Transactional(rollbackFor = Exception.class) public List> saveGeneralOpd(List> dataList) throws Exception { List> results = new ArrayList<>(); - Integer vanID = campConfigService.getVanID(); Integer parkingPlaceID = campConfigService.getParkingPlaceID(); for (Map data : dataList) { Long beneficiaryRegID = getLong(data, "beneficiaryRegID"); if (beneficiaryRegID == null) throw new Exception("beneficiaryRegID is required"); + Integer vanID = campConfigService.resolveVanID(getInt(data, "vanID")); Integer providerServiceMapID = getInt(data, "providerServiceMapID"); String createdBy = getString(data, "createdBy"); + + // New payload (chiefComplaints[] / prescription.drugs[]): AMRIT standard tables only, with dispensing. + // tb_stoptb_general_opd is not written; getAll and the Nikshay export read the standard tables. + if (data.get("chiefComplaints") instanceof List || data.get("prescription") instanceof Map) { + if (providerServiceMapID == null) throw new Exception("providerServiceMapID is required"); + if (createdBy == null || createdBy.isBlank()) throw new Exception("createdBy is required"); + String submissionId = getString(data, "submissionId"); + Map previous = stopTBPrescriptionService.findPreviousSubmission(beneficiaryRegID, submissionId); + if (previous != null) { + results.add(previous); + continue; + } + BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, providerServiceMapID, + createdBy, vanID, parkingPlaceID); + Map result = new LinkedHashMap<>(); + result.put("beneficiaryRegID", beneficiaryRegID); + result.put("visitCode", visit.getVisitCode()); + stopTBPrescriptionService.saveChiefComplaints(toMapList(data.get("chiefComplaints")), beneficiaryRegID, + visit, createdBy, vanID, parkingPlaceID); + if (data.get("prescription") instanceof Map) { + result.putAll(stopTBPrescriptionService.prescribeAndDispense( + (Map) data.get("prescription"), beneficiaryRegID, visit, submissionId, + createdBy, vanID, parkingPlaceID)); + } + results.add(result); + continue; + } + + // Old app payload (free-text chiefComplaint / medication): unchanged behaviour. BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, providerServiceMapID, createdBy, vanID, parkingPlaceID); @@ -403,13 +450,30 @@ public List> saveGeneralOpd(List> dataLi return results; } + @SuppressWarnings("unchecked") + private List> toMapList(Object v) { + return v instanceof List ? (List>) v : null; + } + + // Standard tables first (visits saved with the new payload); for older visits, which exist only in + // tb_stoptb_general_opd, fall back to that table. Same response fields either way. @Override public Map getAllGeneralOpd(Integer providerServiceMapID, Integer villageID) throws Exception { + List> items = stopTBPrescriptionService.getStandardOpdRecords(providerServiceMapID, villageID); + Set standardVisitCodes = new HashSet<>(); + for (Map item : items) standardVisitCodes.add((Long) item.get("visitCode")); + List list = (villageID != null) ? generalOpdRepo.findAllByProviderServiceMapIDAndVillageID(providerServiceMapID, villageID) : generalOpdRepo.findAllByProviderServiceMapID(providerServiceMapID); - List> items = new ArrayList<>(); - for (StopTBGeneralOpd o : list) items.add(opdToMap(o)); + for (StopTBGeneralOpd o : list) { + if (o.getVisitCode() == null || !standardVisitCodes.contains(o.getVisitCode())) items.add(opdToMap(o)); + } + items.sort((a, b) -> { + Date da = (Date) a.get("createdDate"), db = (Date) b.get("createdDate"); + if (da == null || db == null) return da == null ? (db == null ? 0 : 1) : -1; + return db.compareTo(da); + }); Map result = new HashMap<>(); result.put("data", items); result.put("count", items.size()); @@ -427,6 +491,7 @@ private Map opdToMap(StopTBGeneralOpd o) { m.put("dosage", o.getDosage()); m.put("frequency", o.getFrequency()); m.put("duration", o.getDuration()); + m.put("drugs", Collections.emptyList()); // old free-text records have no per-drug details m.put("notes", o.getNotes()); m.put("createdBy", o.getCreatedBy()); m.put("createdDate", o.getCreatedDate()); @@ -514,6 +579,61 @@ public Map getAllDiagnostics(Integer providerServiceMapID, Integ return result; } + // ── By id, for the changes feed ─────────────────────────────────────────── + + @Override + public Map> getNurseTBScreeningsByIds(Collection ids) { + Map> out = new LinkedHashMap<>(); + for (TBScreening s : tbScreeningRepo.findAllById(ids)) { + if (!Boolean.TRUE.equals(s.getDeleted())) out.put(s.getId(), screeningToMap(s)); + } + return out; + } + + @Override + public Map> getGeneralExaminationsByIds(Collection ids) { + Map> out = new LinkedHashMap<>(); + for (StopTBGeneralExamination e : generalExaminationRepo.findAllById(ids)) { + if (!Boolean.TRUE.equals(e.getDeleted())) out.put(e.getId(), examToMap(e)); + } + return out; + } + + @Override + public Map> getDiagnosticsByIds(Collection ids) { + Map> out = new LinkedHashMap<>(); + for (StopTBDiagnostics d : diagnosticsRepo.findAllById(ids)) { + if (!Boolean.TRUE.equals(d.getDeleted())) out.put(d.getId(), diagnosticsToMap(d)); + } + return out; + } + + @Override + public Map> getGeneralOpdByVisitIds(Collection benVisitIds) { + Map> out = new LinkedHashMap<>(); + for (Map m : stopTBPrescriptionService.getStandardOpdRecordsByVisitIds(benVisitIds)) { + out.put((Long) m.get("id"), m); + } + return out; + } + + @Override + public Map> getLegacyGeneralOpdByIds(Collection ids) { + List rows = new ArrayList<>(); + Set visitCodes = new HashSet<>(); + for (StopTBGeneralOpd o : generalOpdRepo.findAllById(ids)) { + if (Boolean.TRUE.equals(o.getDeleted())) continue; + rows.add(o); + if (o.getVisitCode() != null) visitCodes.add(o.getVisitCode()); + } + Set standard = stopTBPrescriptionService.visitCodesWithStandardOpd(visitCodes); + Map> out = new LinkedHashMap<>(); + for (StopTBGeneralOpd o : rows) { + if (o.getVisitCode() == null || !standard.contains(o.getVisitCode())) out.put(o.getId(), opdToMap(o)); + } + return out; + } + private Map diagnosticsToMap(StopTBDiagnostics d) { Map m = new LinkedHashMap<>(); m.put("id", d.getId()); @@ -562,10 +682,33 @@ private Map getRegistrationExtras(Long beneficiaryRegID) { return Collections.emptyMap(); } + // Latest non-null height/weight/bmi/temperatureValue for the beneficiary. Identity-API's + // syncDataToAmrit writes these to t_phy_anthropometry / t_phy_vitals at registration; + // otherFields is only a fallback for beneficiaries registered before that. + private Map getLatestAnthropometry(Long beneficiaryRegID) { + Map values = new HashMap<>(); + for (BenAnthropometryDetail a : benAnthropometryRepo.findByBeneficiaryRegIDOrderByCreatedDateDesc(beneficiaryRegID)) { + if (a.getHeightCm() != null) values.putIfAbsent("height", a.getHeightCm()); + if (a.getWeightKg() != null) values.putIfAbsent("weight", a.getWeightKg()); + if (a.getBmi() != null) values.putIfAbsent("bmi", a.getBmi()); + } + for (BenPhysicalVitalDetail v : benPhysicalVitalRepo.findByBeneficiaryRegIDOrderByCreatedDateDesc(beneficiaryRegID)) { + if (v.getTemperature() != null) { + values.put("temperatureValue", v.getTemperature()); + break; + } + } + Map extras = getRegistrationExtras(beneficiaryRegID); + for (String key : List.of("height", "weight", "bmi", "temperatureValue")) { + if (extras.get(key) instanceof Number) values.putIfAbsent(key, extras.get(key)); + } + return values; + } + private void dualWriteExamToStandardTables(StopTBGeneralExamination exam, Long beneficiaryRegID, BenVisitDetail visit, String createdBy, Integer vanID, Integer parkingPlaceID) { try { - Map extras = getRegistrationExtras(beneficiaryRegID); + Map extras = getLatestAnthropometry(beneficiaryRegID); writeAnthropometry(extras, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); writeVitals(exam, extras, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); writePhyGeneralExam(exam, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); @@ -579,6 +722,9 @@ private void dualWriteExamToStandardTables(StopTBGeneralExamination exam, Long b private void writeAnthropometry(Map extras, Long beneficiaryRegID, BenVisitDetail visit, String createdBy, Integer vanID, Integer parkingPlaceID) { + // An all-null row would become the latest one and hide the registration values + if (!(extras.get("height") instanceof Number) && !(extras.get("weight") instanceof Number) + && !(extras.get("bmi") instanceof Number)) return; try { BenAnthropometryDetail a = new BenAnthropometryDetail(); a.setBeneficiaryRegID(beneficiaryRegID); diff --git a/src/main/java/com/iemr/flw/service/impl/StopTBSyncServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/StopTBSyncServiceImpl.java new file mode 100644 index 000000000..4b144d60a --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/StopTBSyncServiceImpl.java @@ -0,0 +1,483 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParser; +import com.iemr.flw.service.BeneficiaryService; +import com.iemr.flw.service.DiagnosticOrderService; +import com.iemr.flw.service.DynamicFormResponseService; +import com.iemr.flw.service.StopTBService; +import com.iemr.flw.service.StopTBSyncService; +import com.iemr.flw.service.TBConfirmedCaseService; +import com.iemr.flw.service.TBSuspectedService; +import com.iemr.flw.service.sync.StopTBSyncType; +import com.iemr.flw.service.sync.SyncToken; +import com.iemr.flw.service.sync.UserSyncScope; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * STOP-TB changes feed. AMRIT-DB V132 / V32 install t_sync_change_log and its triggers on every + * server; tablets call the feed on their camp hub (or UAT central when testing). + * + * The tablet keeps one opaque token. With none it gets a first full download in pages (snapshot); + * after that, each call returns only the records with change-log lines after its token, in their + * current state, plus the next token. Village scope is resolved here through i_ben_flow_outreach, + * the same way today's getAll endpoints do. + * + * @author Piramal Swasthya + */ +@Service +public class StopTBSyncServiceImpl implements StopTBSyncService { + + private final Logger logger = LoggerFactory.getLogger(StopTBSyncServiceImpl.class); + + static final int DEFAULT_LIMIT = 200; + static final int MAX_LIMIT = 500; + /** + * Beneficiary records are the expensive ones (several identity lookups and a FHIR call each), so a + * page carries at most this many; the token resumes from the last one sent. + */ + static final int MAX_BENEFICIARIES_PER_PAGE = 25; + /** Margin under the oldest open transaction (see safePoint); lines younger than this wait. */ + static final int SAFE_LAG_SECONDS = 5; + /** The hub keeps 30 days of log; a token older than this may point at cleaned-up lines. */ + static final long MAX_TOKEN_AGE_SECONDS = 29L * 24 * 3600; + private static final long SUPPORT_CHECK_TTL_MS = 5 * 60 * 1000L; + private static final String FLOW_TABLE = "db_iemr.i_ben_flow_outreach"; + + // Same date formats the existing getAll endpoints use for these records. + private final Gson stopTbGson = new GsonBuilder().serializeNulls().create(); + + @PersistenceContext(unitName = "db_iemr") + private EntityManager em; + + @Autowired + private BeneficiaryService beneficiaryService; + @Autowired + private StopTBService stopTBService; + @Autowired + private TBSuspectedService tbSuspectedService; + @Autowired + private TBConfirmedCaseService tbConfirmedCaseService; + @Autowired + private DynamicFormResponseService dynamicFormResponseService; + @Autowired + private DiagnosticOrderService diagnosticOrderService; + @Autowired + private ObjectMapper objectMapper; + + private static final long USER_SCOPE_TTL_MS = 5 * 60 * 1000L; + private final Map> userScopes = new java.util.concurrent.ConcurrentHashMap<>(); + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; + + private volatile boolean innodbTrxWarned; + private volatile Boolean supported; + private volatile long supportCheckedAt; + + @Override + public Map getChanges(Integer userId, String token, Integer providerServiceMapID, + List villageIds, List types, Integer limit, + String authorisation) { + if (!isSupported()) { + Map out = new LinkedHashMap<>(); + out.put("supported", false); + return out; + } + if (userId == null) throw new IllegalArgumentException("A valid JwtToken is required"); + if (providerServiceMapID == null) throw new IllegalArgumentException("providerServiceMapID is required"); + // Only the user's own service and villages; none asked for means all of them. + List villages = userScope(userId).resolve(providerServiceMapID, villageIds); + int pageSize = limit == null || limit <= 0 ? DEFAULT_LIMIT : Math.min(limit, MAX_LIMIT); + + String serverId = serverId(); + SyncToken parsed = SyncToken.parse(token); + long now = System.currentTimeMillis() / 1000; + boolean usable = parsed != null && serverId.equals(parsed.serverId()) + && (parsed.kind() == SyncToken.Kind.SNAPSHOT || now - parsed.issuedAt() <= MAX_TOKEN_AGE_SECONDS); + + Scope scope = new Scope(providerServiceMapID, villages, requestedTypes(types)); + // A token covers only the types and villages it was issued for; anything else needs a snapshot. + usable = usable && parsed.typesMask() == scope.typesMask() && parsed.scopeHash() == scope.scopeHash(); + if (!usable) { + if (parsed != null) logger.info("Sync token {} not usable here, starting a snapshot", parsed); + return snapshotPage(serverId, SyncToken.snapshot(serverId, safePoint(), 0, 0, scope.typesMask(), scope.scopeHash()), + scope, pageSize, authorisation); + } + return parsed.kind() == SyncToken.Kind.SNAPSHOT + ? snapshotPage(serverId, parsed, scope, pageSize, authorisation) + : deltaPage(serverId, parsed.seq(), scope, pageSize, authorisation); + } + + // ── Snapshot: everything in scope, type by type, keyset-paged ───────────── + + private Map snapshotPage(String serverId, SyncToken at, Scope scope, int pageSize, + String authorisation) { + StopTBSyncType[] types = StopTBSyncType.values(); + int typeIndex = at.typeIndex(); + long after = at.afterKey(); + List> items = new ArrayList<>(); + + while (items.size() < pageSize && typeIndex < types.length) { + StopTBSyncType type = types[typeIndex]; + if (!scope.types.contains(type)) { + typeIndex++; + after = 0; + continue; + } + int want = pageSize - items.size(); + if (type == StopTBSyncType.BENEFICIARY) want = Math.min(want, MAX_BENEFICIARIES_PER_PAGE); + List keys = snapshotKeys(type, scope, after, want); + Map records = build(type, keys, authorisation); + for (Long key : keys) { + String data = records.get(key); + if (data != null) items.add(item(type, "upsert", key, at.seq(), data)); + } + if (keys.size() < want) { + typeIndex++; + after = 0; + } else { + after = keys.get(keys.size() - 1); + break; + } + } + + boolean done = typeIndex >= types.length; + SyncToken next = done + ? SyncToken.delta(serverId, at.seq(), System.currentTimeMillis() / 1000, scope.typesMask(), scope.scopeHash()) + : SyncToken.snapshot(serverId, at.seq(), typeIndex, after, scope.typesMask(), scope.scopeHash()); + return page(serverId, true, items, next, !done); + } + + @SuppressWarnings("unchecked") + private List snapshotKeys(StopTBSyncType type, Scope scope, long after, int limit) { + List rows = em.createNativeQuery(type.snapshotKeySql()) + .setParameter("psm", scope.psm) + .setParameter("villages", scope.villages) + .setParameter("after", after) + .setParameter("limit", limit) + .getResultList(); + List keys = new ArrayList<>(rows.size()); + for (Object r : rows) keys.add(((Number) r).longValue()); + return keys; + } + + // ── Delta: records with log lines after the token ───────────────────────── + + @SuppressWarnings("unchecked") + private Map deltaPage(String serverId, long from, Scope scope, int pageSize, + String authorisation) { + long safe = Math.max(safePoint(), from); + // One row per record: its latest line in range, and that line's op. Deduplicates a record + // changed many times since the token. + List rows = em.createNativeQuery( + "SELECT l.entity, l.row_pk, l.seq, l.op, g.scoped FROM db_iemr.t_sync_change_log l JOIN (" + + " SELECT c.entity, c.row_pk, MAX(c.seq) AS last_seq, MAX(c.op = 'S') AS scoped " + + " FROM db_iemr.t_sync_change_log c " + + " WHERE c.seq > :from AND c.seq <= :safe AND c.entity IN (:entities) AND (" + + " (c.ben_reg_id IS NOT NULL AND EXISTS (SELECT 1 FROM db_iemr.i_ben_flow_outreach f " + + " WHERE f.beneficiary_reg_id = c.ben_reg_id AND f.providerServiceMapID = :psm AND f.villageID IN (:villages)))" + + " OR (c.beneficiary_id IS NOT NULL AND EXISTS (SELECT 1 FROM db_iemr.i_ben_flow_outreach f " + + " WHERE f.beneficiary_id = c.beneficiary_id AND f.providerServiceMapID = :psm AND f.villageID IN (:villages))))" + + " GROUP BY c.entity, c.row_pk ORDER BY last_seq LIMIT :limit" + + ") g ON l.seq = g.last_seq ORDER BY l.seq") + .setParameter("from", from) + .setParameter("safe", safe) + .setParameter("entities", scope.logEntities()) + .setParameter("psm", scope.psm) + .setParameter("villages", scope.villages) + .setParameter("limit", pageSize) + .getResultList(); + boolean full = rows.size() == pageSize; + + // Keep beneficiary records per page bounded: stop before the one over the cap. The token then + // resumes from the last row kept, so nothing after it is skipped. + int beneficiaries = 0; + for (int i = 0; i < rows.size(); i++) { + if (!StopTBSyncType.BENEFICIARY.logEntity().equals(rows.get(i)[0])) continue; + if (++beneficiaries > MAX_BENEFICIARIES_PER_PAGE) { + rows = new ArrayList<>(rows.subList(0, i)); + full = true; + break; + } + } + + // Build each type's records in one batch, then emit in log order. + Map> keysByType = new EnumMap<>(StopTBSyncType.class); + for (Object[] r : rows) { + StopTBSyncType type = StopTBSyncType.fromLogEntity((String) r[0]); + if (type != null) keysByType.computeIfAbsent(type, t -> new ArrayList<>()).add(((Number) r[1]).longValue()); + } + Map> built = new EnumMap<>(StopTBSyncType.class); + keysByType.forEach((type, keys) -> built.put(type, build(type, keys, authorisation))); + + List> items = new ArrayList<>(); + // Beneficiaries that came into scope (op 'S': new flow row, or a village / service change): + // their records logged before that never passed the scope check, so send them now. + List scopedRegIds = new ArrayList<>(); + Map scopedSeq = new HashMap<>(); + for (Object[] r : rows) { + if (StopTBSyncType.BENEFICIARY.logEntity().equals(r[0]) && r[4] != null && ((Number) r[4]).intValue() == 1) { + long regId = ((Number) r[1]).longValue(); + scopedRegIds.add(regId); + scopedSeq.put(regId, ((Number) r[2]).longValue()); + } + } + long lastSeq = from; + for (Object[] r : rows) { + lastSeq = ((Number) r[2]).longValue(); + StopTBSyncType type = StopTBSyncType.fromLogEntity((String) r[0]); + if (type == null) continue; + long key = ((Number) r[1]).longValue(); + String data = built.get(type).get(key); + String op = r[3] == null ? "U" : r[3].toString(); + if (data != null && !"D".equals(op)) { + items.add(item(type, "upsert", key, lastSeq, data)); + } else if ("D".equals(op) || type != StopTBSyncType.BENEFICIARY) { + // Gone, soft-deleted or no longer a record the app keeps (e.g. an OPD visit with no + // complaint or drug). A beneficiary that just failed to build is never deleted on the + // tablet; only a deleted mapping removes it. + items.add(item(type, "delete", key, lastSeq, null)); + } + } + + if (!scopedRegIds.isEmpty()) { + long version = scopedSeq.values().stream().mapToLong(Long::longValue).max().orElse(lastSeq); + for (StopTBSyncType type : scope.types) { + if (type == StopTBSyncType.BENEFICIARY) continue; + List keys = keysForBeneficiaries(type, scope, scopedRegIds); + List alreadySent = keysByType.getOrDefault(type, List.of()); + keys.removeAll(alreadySent); + if (keys.isEmpty()) continue; + Map records = build(type, keys, authorisation); + for (Long key : keys) { + String data = records.get(key); + if (data != null) items.add(item(type, "upsert", key, version, data)); + } + } + } + + boolean hasMore = full; + long nextSeq = hasMore ? lastSeq : safe; + return page(serverId, false, items, + SyncToken.delta(serverId, nextSeq, System.currentTimeMillis() / 1000, scope.typesMask(), scope.scopeHash()), hasMore); + } + + @SuppressWarnings("unchecked") + private List keysForBeneficiaries(StopTBSyncType type, Scope scope, List regIds) { + jakarta.persistence.Query q = em.createNativeQuery(type.keysForBeneficiariesSql()).setParameter("regIds", regIds); + if (type.keysForBeneficiariesSql().contains(":psm")) q.setParameter("psm", scope.psm); + List rows = q.getResultList(); + List keys = new ArrayList<>(rows.size()); + for (Object r : rows) keys.add(((Number) r).longValue()); + return keys; + } + + // ── Records, in the same JSON each type's existing endpoint returns ─────── + + private Map build(StopTBSyncType type, List keys, String authorisation) { + Map out = new HashMap<>(); + if (keys.isEmpty()) return out; + try { + switch (type) { + case BENEFICIARY: + return beneficiaryService.getBeneficiaryRecordsByRegIds(keys, authorisation); + case TB_SCREENING: + stopTBService.getNurseTBScreeningsByIds(keys).forEach((k, m) -> out.put(k, stopTbGson.toJson(m))); + return out; + case GENERAL_EXAMINATION: + stopTBService.getGeneralExaminationsByIds(keys).forEach((k, m) -> out.put(k, stopTbGson.toJson(m))); + return out; + case GENERAL_OPD: + stopTBService.getGeneralOpdByVisitIds(keys).forEach((k, m) -> out.put(k, stopTbGson.toJson(m))); + return out; + case GENERAL_OPD_LEGACY: + stopTBService.getLegacyGeneralOpdByIds(keys).forEach((k, m) -> out.put(k, stopTbGson.toJson(m))); + return out; + case DIAGNOSTICS: + stopTBService.getDiagnosticsByIds(keys).forEach((k, m) -> out.put(k, stopTbGson.toJson(m))); + return out; + case TB_SUSPECTED: + return tbSuspectedService.getRecordsByIds(keys); + case TB_CONFIRMED: + return tbConfirmedCaseService.getRecordsByIds(keys); + case FORM_RESPONSE: + for (Map.Entry e : dynamicFormResponseService.getResponsesByIds(keys).entrySet()) { + out.put(e.getKey(), objectMapper.writeValueAsString(e.getValue())); + } + return out; + case DIAGNOSTIC_ORDER: + for (Map.Entry> e : diagnosticOrderService.getOrderRecordsByIds(keys).entrySet()) { + out.put(e.getKey(), objectMapper.writeValueAsString(e.getValue())); + } + return out; + default: + return out; + } + } catch (Exception e) { + // A failed batch must not turn into deletes on the tablet: fail the whole call, so the + // token doesn't move and the tablet retries. + throw new IllegalStateException("Could not build " + type.apiName() + " records: " + e.getMessage(), e); + } + } + + private Map item(StopTBSyncType type, String op, long key, long version, String data) { + Map m = new LinkedHashMap<>(); + m.put("type", type.apiName()); + m.put("op", op); + m.put("key", key); + m.put("version", version); + // The record exactly as the type's existing endpoint returns it, so the app reuses its parser. + m.put("data", data == null ? null : JsonParser.parseString(data)); + return m; + } + + private Map page(String serverId, boolean snapshot, List> items, + SyncToken next, boolean hasMore) { + Map out = new LinkedHashMap<>(); + out.put("supported", true); + out.put("serverId", serverId); + out.put("snapshot", snapshot); + out.put("items", items); + out.put("nextToken", next.encode()); + out.put("hasMore", hasMore); + return out; + } + + // The user's services and villages from their role mappings, cached briefly because tablets poll. + private UserSyncScope userScope(Integer userId) { + long now = System.currentTimeMillis(); + Map.Entry cached = userScopes.get(userId); + if (cached != null && now - cached.getKey() < USER_SCOPE_TTL_MS) return cached.getValue(); + UserSyncScope scope = UserSyncScope.fromMappingRows(userServiceRoleRepo.getServiceVillageRows(userId)); + userScopes.put(userId, Map.entry(now, scope)); + return scope; + } + + // ── Hub state ───────────────────────────────────────────────────────────── + + private String serverId() { + return String.valueOf(em.createNativeQuery("SELECT @@server_uuid").getSingleResult()); + } + + /** + * The highest seq a reader may move past. seq is taken when a row is inserted, not when its + * transaction commits, so a transaction still open may hold a lower seq than lines already + * committed. Every line it writes is stamped at or after its start, so lines older than the oldest + * open transaction (information_schema.innodb_trx) are final; the lag also covers the gap between a + * statement's timestamp and its insert. A long open transaction holds the feed back until it ends. + */ + private long safePoint() { + try { + Object r = em.createNativeQuery("SELECT COALESCE(MAX(seq), 0) FROM db_iemr.t_sync_change_log " + + "WHERE changed_at <= (SELECT LEAST(NOW(6), COALESCE(MIN(trx_started), NOW(6))) " + + "FROM information_schema.innodb_trx) - INTERVAL " + SAFE_LAG_SECONDS + " SECOND") + .getSingleResult(); + return ((Number) r).longValue(); + } catch (Exception e) { + // innodb_trx needs the PROCESS privilege; without it only the fixed lag protects late commits. + if (!innodbTrxWarned) { + logger.warn("STOP-TB changes feed: cannot read information_schema.innodb_trx ({}); " + + "using a fixed {} s lag only", e.getMessage(), SAFE_LAG_SECONDS); + innodbTrxWarned = true; + } + Object r = em.createNativeQuery("SELECT COALESCE(MAX(seq), 0) FROM db_iemr.t_sync_change_log " + + "WHERE changed_at <= NOW(6) - INTERVAL " + SAFE_LAG_SECONDS + " SECOND") + .getSingleResult(); + return ((Number) r).longValue(); + } + } + + /** + * True only where the change log exists AND every source table has its insert, update and delete + * triggers. Otherwise a change could be missed silently, so the feed reports itself unsupported and + * the app keeps using the full pull. + */ + @SuppressWarnings("unchecked") + boolean isSupported() { + long now = System.currentTimeMillis(); + if (supported != null && now - supportCheckedAt < SUPPORT_CHECK_TTL_MS) return supported; + boolean ok; + try { + Number logTables = (Number) em.createNativeQuery("SELECT COUNT(*) FROM information_schema.tables " + + "WHERE table_schema = 'db_iemr' AND table_name = 't_sync_change_log'").getSingleResult(); + Set withAllTriggers = new HashSet<>(); + List rows = em.createNativeQuery("SELECT LOWER(CONCAT(event_object_schema, '.', event_object_table)), " + + "COUNT(DISTINCT event_manipulation) FROM information_schema.triggers " + + "WHERE trigger_name LIKE 'trg\\_scl\\_%' GROUP BY event_object_schema, event_object_table").getResultList(); + for (Object[] r : rows) { + String table = (String) r[0]; + // The flow table only decides scope: insert and update are enough (rows are never deleted). + int needed = FLOW_TABLE.equals(table) ? 2 : 3; + if (((Number) r[1]).intValue() >= needed) withAllTriggers.add(table); + } + List missing = new ArrayList<>(); + for (StopTBSyncType type : StopTBSyncType.values()) { + for (String table : type.sourceTables()) { + if (!withAllTriggers.contains(table)) missing.add(table); + } + } + ok = logTables.intValue() > 0 && missing.isEmpty(); + if (logTables.intValue() > 0 && !missing.isEmpty()) { + logger.error("STOP-TB changes feed disabled: change-log triggers missing on {}", missing); + } + } catch (Exception e) { + logger.warn("STOP-TB changes feed: could not check the change log: {}", e.getMessage()); + ok = false; + } + supported = ok; + supportCheckedAt = now; + return ok; + } + + private static Set requestedTypes(List names) { + Set out = EnumSet.noneOf(StopTBSyncType.class); + if (names == null || names.isEmpty()) { + out.addAll(EnumSet.allOf(StopTBSyncType.class)); + return out; + } + for (StopTBSyncType t : StopTBSyncType.values()) { + if (names.contains(t.apiName())) out.add(t); + } + if (out.isEmpty()) throw new IllegalArgumentException("No known record types in " + names); + return out; + } + + private static final class Scope { + final Integer psm; + final List villages; + final Set types; + + Scope(Integer psm, List villages, Set types) { + this.psm = psm; + this.villages = villages; + this.types = types; + } + + long scopeHash() { + return UserSyncScope.scopeHash(psm, villages); + } + + long typesMask() { + long mask = 0; + for (StopTBSyncType t : types) mask |= 1L << t.ordinal(); + return mask; + } + + List logEntities() { + List out = new ArrayList<>(); + for (StopTBSyncType t : types) out.add(t.logEntity()); + return out; + } + } +} 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 faf95f2fd..2db58ede3 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -1,15 +1,15 @@ package com.iemr.flw.service.impl; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.iemr.flw.domain.iemr.*; -import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; -import com.iemr.flw.dto.iemr.TbReferralFollowUpListDTO; -import com.iemr.flw.dto.iemr.TbTptFollowUpDTO; -import com.iemr.flw.dto.iemr.TbTptFollowUpListDTO; +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.BenVisitDetail; import com.iemr.flw.repo.identity.BeneficiaryRepo; -import com.iemr.flw.repo.iemr.*; +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.TbCounsellingV2FormSeeder; import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.CampConfigService; @@ -25,9 +25,12 @@ import java.sql.Timestamp; import java.time.LocalDate; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.*; +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 @@ -54,14 +57,6 @@ public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { @Autowired private BeneficiaryRepo beneficiaryRepo; - @Autowired - private TbReferralFollowUpRepo tbReferralFollowUpRepo; - - @Autowired - private IncentiveLogicImpl incentiveLogic; - - @Autowired - private TbTptFollowUpRepo tbTptFollowUpRepo; public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository, FormResponseRepo formResponseRepo, DynamicFormRepo dynamicFormRepo) { @@ -146,37 +141,21 @@ private void checkIncentive(TBConfirmedCase entity){ || "Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen); if (Boolean.TRUE.equals(entity.getTreatmentCompleted()) - && entity.getFollowUpDate() != null) { + && entity.getExpectedTreatmentCompletionDate() != null) { if (isDrTb) { - if("Shorter Regimen (9–12 Months)".equalsIgnoreCase(regimen)){ - if ("cured".equalsIgnoreCase(entity.getTreatmentOutcome())) { - incentiveLogicService.incentiveForTbFollowUpIsDrTb( - entity.getBenId(), - Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), - Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), - entity.getUserId() - ); - } - - }else if("Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen)){ - if ("cured".equalsIgnoreCase(entity.getTreatmentOutcome())) { - - incentiveLogicService.incentiveForTbFollowUpIsDrTb( - entity.getBenId(), - Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), - Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), - entity.getUserId() - ); - } - } - + incentiveLogicService.incentiveForTbFollowUpIsDrTb( + entity.getBenId(), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + entity.getUserId() + ); } else { incentiveLogicService.incentiveForTbFollowUp( entity.getBenId(), - Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), - Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), entity.getUserId() ); @@ -185,24 +164,6 @@ private void checkIncentive(TBConfirmedCase entity){ } } - public boolean isEligibleForIncentive(LocalDate treatmentStartDate, LocalDate endDate,Integer minMonth) { - - if (treatmentStartDate == null || endDate == null) { - return false; - } - - LocalDate start = treatmentStartDate.atStartOfDay() - .atZone(ZoneId.systemDefault()) - .toLocalDate(); - - LocalDate end = endDate.atStartOfDay() - .atZone(ZoneId.systemDefault()) - .toLocalDate(); - - return end.isAfter(start.plusMonths(minMonth)) - || end.isEqual(start.plusMonths(minMonth)); - } - @Override public String getByBenId(Long benId, String authorisation) throws Exception { OutputResponse response = new OutputResponse(); @@ -244,430 +205,24 @@ public String getByProviderServiceMapId(Integer providerServiceMapID, Integer vi } @Override - public String saveReferralFollowUp(TbReferralFollowUpDTO requestDTO, String token) { - OutputResponse response = new OutputResponse(); - - try { - - TbReferralFollowUp tbReferralFollowUp = new TbReferralFollowUp(); - - if(!token.isEmpty() && token!=null && requestDTO!=null){ - String userName = jwtUtil.extractUsername(token); - Integer userId = jwtUtil.extractUserId(token); - tbReferralFollowUp.setBenId(requestDTO.getBenId()); - tbReferralFollowUp.setHouseHoldId(requestDTO.getHouseHoldId()); - tbReferralFollowUp.setSyncedBy(userName); - tbReferralFollowUp.setUpdatedBy(userName); - tbReferralFollowUp.setCreatedBy(userName); - tbReferralFollowUp.setUserId(userId); - if(requestDTO.getFields().getReferredOnDate()!=null && !requestDTO.getFields().getFollowUpDate().isEmpty()){ - Timestamp referOnDate = Timestamp.valueOf(requestDTO.getFields().getReferredOnDate()); - tbReferralFollowUp.setFollowUpDate(referOnDate); - - } - - if(requestDTO.getFields().getFollowUpDate()!=null && !requestDTO.getFields().getFollowUpDate().isEmpty()){ - Timestamp followUpDate = Timestamp.valueOf(requestDTO.getFields().getFollowUpDate()); - tbReferralFollowUp.setFollowUpDate(followUpDate); - - } - tbReferralFollowUp.setFollowUpStatus(requestDTO.getFields().getFollowUpStatus()); - } - - tbReferralFollowUpRepo.save(tbReferralFollowUp); - response.setResponse("TB Referral follow up saved successfully"); - - - - }catch (Exception e){ - response.setError(500,e.getMessage()); - return response.toString(); - } - - - return response.toString(); - } - - @Override - public String getReferralFollowUp(String token) { - OutputResponse response = new OutputResponse(); - - try { - if (token == null || token.trim().isEmpty()) { - response.setError(400, "Token is required"); - return response.toString(); - } - - Integer userId = jwtUtil.extractUserId(token); - - List referrals = - tbReferralFollowUpRepo.findByUserId(userId); - - List referralDTOs = new ArrayList<>(); - - DateTimeFormatter formatter = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - - for (TbReferralFollowUp referral : referrals) { - - TbReferralFollowUpDTO dto = new TbReferralFollowUpDTO(); - dto.setBenId(referral.getBenId()); - dto.setUserId(referral.getUserId()); - dto.setHouseHoldId(referral.getHouseHoldId()); - - // Initialize nested DTO before setting fields - TbReferralFollowUpListDTO fields = - new TbReferralFollowUpListDTO(); - - if (referral.getReferredOnDate() != null) { - fields.setReferredOnDate( - referral.getReferredOnDate() - .toLocalDateTime() - .format(formatter) - ); - } - - if (referral.getFollowUpDate() != null) { - fields.setFollowUpDate( - referral.getFollowUpDate() - .toLocalDateTime() - .format(formatter) - ); - } - - fields.setFollowUpStatus(referral.getFollowUpStatus()); - - dto.setFields(fields); - referralDTOs.add(dto); - } - - ObjectMapper objectMapper = new ObjectMapper(); - - response.setResponse( - objectMapper.writeValueAsString(referralDTOs) - ); - - } catch (Exception e) { - // Replace with your project's logger if available - e.printStackTrace(); - response.setError(500, "Failed to fetch referral follow-up: " + e.getMessage()); - } - - return response.toString(); - } - - @Override - public String saveTptFollowUp(TbTptFollowUpDTO requestDTO, String token) { - - OutputResponse response = new OutputResponse(); - - try { - - TbTptFollowUp tbTptFollowUp = new TbTptFollowUp(); - - if (token != null && !token.isEmpty() && requestDTO != null) { - - String userName = jwtUtil.extractUsername(token); - Integer userId = jwtUtil.extractUserId(token); - - tbTptFollowUp.setBenId(requestDTO.getBenId()); - tbTptFollowUp.setUserId(userId); - - tbTptFollowUp.setCreatedBy(userName); - tbTptFollowUp.setUpdatedBy(userName); - - if (requestDTO.getFields() != null) { - - TbTptFollowUpListDTO fields = requestDTO.getFields(); - - tbTptFollowUp.setRegimenType(fields.getRegimenType()); - - if (fields.getTreatmentStartDate() != null - && !fields.getTreatmentStartDate().isEmpty()) { - - tbTptFollowUp.setTreatmentStartDate( - Timestamp.valueOf(fields.getTreatmentStartDate()) - ); - } - - if (fields.getExpectedTreatmentCompletionDate() != null - && !fields.getExpectedTreatmentCompletionDate().isEmpty()) { - - tbTptFollowUp.setExpectedTreatmentCompletionDate( - Timestamp.valueOf(fields.getExpectedTreatmentCompletionDate()) - ); - } - - if (fields.getFollowUpDate() != null - && !fields.getFollowUpDate().isEmpty()) { - - tbTptFollowUp.setFollowUpDate( - Timestamp.valueOf(fields.getFollowUpDate()) - ); - } - - tbTptFollowUp.setFollowUpMonth( - fields.getMonthlyFollowUp() - ); - - tbTptFollowUp.setAdherenceToMedicines( - fields.getMedicineAdherence() - ); - - tbTptFollowUp.setAnyDiscomfort( - convertBollen(fields.getAnyDiscomfort()) - ); - - tbTptFollowUp.setTreatmentCompleted( - convertBollen(fields.getTreatmentCompleted()) - ); - - if (fields.getActualCompletionDate() != null - && !fields.getActualCompletionDate().isEmpty()) { - - tbTptFollowUp.setActualTreatmentCompletionDate( - Timestamp.valueOf(fields.getActualCompletionDate()) - ); - } - - tbTptFollowUp.setTptOutcome( - fields.getTptOutcome() - ); - - if ("Death".equalsIgnoreCase(fields.getTptOutcome())) { - - if (fields.getDateOfDeath() != null - && !fields.getDateOfDeath().isEmpty()) { - - tbTptFollowUp.setDateOfDeath( - Timestamp.valueOf(fields.getDateOfDeath()) - ); - } - - tbTptFollowUp.setPlaceOfDeath( - fields.getPlaceOfDeath() - ); - - tbTptFollowUp.setReasonForDeath( - fields.getReasonForDeath() - ); - } - } - - tbTptFollowUpRepo.save(tbTptFollowUp); - - createTptIncentiveIfEligible(tbTptFollowUp); - } - - response.setResponse("TPT follow up saved successfully"); - - } catch (Exception e) { - - response.setError(500, e.getMessage()); - return response.toString(); - } - - return response.toString(); + public Map getRecordsByIds(java.util.Collection ids) { + List intIds = ids.stream().map(Long::intValue).collect(Collectors.toList()); + List dtoList = withCounselled( + repository.findAllById(intIds).stream().map(this::toDTO).collect(Collectors.toList())); + Gson gson = confirmedGson(); + Map out = new java.util.LinkedHashMap<>(); + for (TBConfirmedCaseDTO dto : dtoList) out.put(dto.getId().longValue(), gson.toJson(dto)); + return out; } - - private static final Map MIN_FOLLOW_UPS = Map.of( - "1HP", 1, - "3HP", 3, - "3RH", 3, - "4R", 4, - "6H", 6, - "6LFX", 6 - ); - - - private void createTptIncentiveIfEligible(TbTptFollowUp saved) { - - // 1. Basic conditions - if (!Boolean.TRUE.equals(saved.getTreatmentCompleted()) - || saved.getActualTreatmentCompletionDate() == null - || saved.getRegimenType() == null - || saved.getTreatmentStartDate() == null - || saved.getBenId() == null) { - return; - } - - // 2. Regimen ka minimum follow-up count - Integer minRequired = MIN_FOLLOW_UPS.get(saved.getRegimenType().trim().toUpperCase()); - if (minRequired == null) { - return; // unknown regimen - } - - List cycleRows = tbTptFollowUpRepo - .findByBenIdAndRegimenTypeAndTreatmentStartDate( - saved.getBenId(), - saved.getRegimenType(), - saved.getTreatmentStartDate()); - - long completedMonths = cycleRows.stream() - .map(TbTptFollowUp::getFollowUpMonth) - .filter(Objects::nonNull) - .map(String::trim) - .distinct() - .count(); - - if (completedMonths < minRequired) { - return; - } - Timestamp completionDate = saved.getActualTreatmentCompletionDate(); - - incentiveLogic.incentiveForTbPreventiveFollowUp( - saved.getBenId(), - completionDate, - completionDate, - saved.getUserId()); - } - - @Override - public String getTptFollowUp(String token) { - - OutputResponse response = new OutputResponse(); - - try { - - if (token == null || token.trim().isEmpty()) { - response.setError(400, "Token is required"); - return response.toString(); - } - - Integer userId = jwtUtil.extractUserId(token); - - List tptFollowUps = - tbTptFollowUpRepo.findByUserId(userId); - - List tptFollowUpDTOs = - new ArrayList<>(); - - DateTimeFormatter formatter = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - - for (TbTptFollowUp tptFollowUp : tptFollowUps) { - - TbTptFollowUpDTO dto = new TbTptFollowUpDTO(); - - dto.setBenId(tptFollowUp.getBenId()); - dto.setUserId(tptFollowUp.getUserId()); - - TbTptFollowUpListDTO fields = - new TbTptFollowUpListDTO(); - - // Regimen Type - fields.setRegimenType( - tptFollowUp.getRegimenType() - ); - - // Treatment Start Date - if (tptFollowUp.getTreatmentStartDate() != null) { - fields.setTreatmentStartDate( - tptFollowUp.getTreatmentStartDate() - .toLocalDateTime() - .format(formatter) - ); - } - - // Expected Treatment Completion Date - if (tptFollowUp.getExpectedTreatmentCompletionDate() != null) { - fields.setExpectedTreatmentCompletionDate( - tptFollowUp.getExpectedTreatmentCompletionDate() - .toLocalDateTime() - .format(formatter) - ); - } - - // Follow Up Date - if (tptFollowUp.getFollowUpDate() != null) { - fields.setFollowUpDate( - tptFollowUp.getFollowUpDate() - .toLocalDateTime() - .format(formatter) - ); - } - - // Monthly Follow Up - fields.setMonthlyFollowUp( - tptFollowUp.getFollowUpMonth() - ); - - // Medicine Adherence - fields.setMedicineAdherence( - tptFollowUp.getAdherenceToMedicines() - ); - - // Any Discomfort - fields.setAnyDiscomfort( - convert(tptFollowUp.getAnyDiscomfort()) - ); - - // Treatment Completed - fields.setTreatmentCompleted( - convert(tptFollowUp.getTreatmentCompleted()) - ); - - // Actual Completion Date - if (tptFollowUp.getActualTreatmentCompletionDate() != null) { - fields.setActualCompletionDate( - tptFollowUp.getActualTreatmentCompletionDate() - .toLocalDateTime() - .format(formatter) - ); - } - - // TPT Outcome - fields.setTptOutcome( - tptFollowUp.getTptOutcome() - ); - - // Date of Death - if (tptFollowUp.getDateOfDeath() != null) { - fields.setDateOfDeath( - tptFollowUp.getDateOfDeath() - .toLocalDateTime() - .format(formatter) - ); - } - - // Place of Death - fields.setPlaceOfDeath( - tptFollowUp.getPlaceOfDeath() - ); - - // Reason for Death - fields.setReasonForDeath( - tptFollowUp.getReasonForDeath() - ); - - dto.setFields(fields); - - tptFollowUpDTOs.add(dto); - } - - ObjectMapper objectMapper = new ObjectMapper(); - - response.setResponse( - objectMapper.writeValueAsString(tptFollowUpDTOs) - ); - - } catch (Exception e) { - - e.printStackTrace(); - - response.setError( - 500, - "Failed to fetch TPT follow-up: " + e.getMessage() - ); - } - - return response.toString(); + private Gson confirmedGson() { + return new GsonBuilder() + .registerTypeAdapter(LocalDate.class, new LocalDateAdapter()) + .setDateFormat("MMM dd, yyyy h:mm:ss a") + .create(); } - private String buildTbConfirmedCasesResponse(Integer userId, List list) { - List dtoList = list.stream().map(this::toDTO).collect(Collectors.toList()); - + private List withCounselled(List dtoList) { List benIds = dtoList.stream().map(TBConfirmedCaseDTO::getBenId).collect(Collectors.toList()); Set counselledBenIds = Collections.emptySet(); if (!benIds.isEmpty()) { @@ -678,15 +233,16 @@ private String buildTbConfirmedCasesResponse(Integer userId, List counselled = counselledBenIds; dtoList.forEach(dto -> dto.setCounselled(counselled.contains(dto.getBenId()))); + return dtoList; + } + + private String buildTbConfirmedCasesResponse(Integer userId, List list) { + List dtoList = withCounselled(list.stream().map(this::toDTO).collect(Collectors.toList())); Map response = new java.util.HashMap<>(); response.put("userId", userId); response.put("tbConfirmedCases", dtoList); - Gson gson = new GsonBuilder() - .registerTypeAdapter(LocalDate.class, new LocalDateAdapter()) - .setDateFormat("MMM dd, yyyy h:mm:ss a") - .create(); - return gson.toJson(response); + return confirmedGson().toJson(response); } // Utility: convert entity -> DTO @@ -715,17 +271,4 @@ private TBConfirmedCaseDTO toDTO(TBConfirmedCase entity) { return dto; } - - private String convert(Boolean value) { - if (value == null) return null; - return value ? "Yes" : "No"; - } - - private Boolean convertBollen(String value) { - if (value != null && !value.isEmpty()) { - return value.equalsIgnoreCase("Yes"); - } else { - return false; - } - } } diff --git a/src/main/java/com/iemr/flw/service/impl/TBStopVisitServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBStopVisitServiceImpl.java index 7297adfc1..d3f3e485f 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBStopVisitServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBStopVisitServiceImpl.java @@ -25,7 +25,17 @@ public BenVisitDetail getOrCreateVisitForToday(Long beneficiaryRegID, Integer pr Timestamp dayEnd = Timestamp.valueOf(today.plusDays(1).atStartOfDay()); BenVisitDetail existing = benVisitDetailsRepo.findStopTBVisitForToday(beneficiaryRegID, dayStart, dayEnd); - if (existing != null) return existing; + if (existing != null) { + // TB suspected / confirmed / diagnostic saves create the visit without a service line; whichever + // form syncs first decides. Fill it from the first later save that has one (screening, OPD...). + if (existing.getProviderServiceMapID() == null && providerServiceMapID != null) { + existing.setProviderServiceMapID(providerServiceMapID); + existing.setModifiedBy(createdBy); + existing.setProcessed("N"); + existing = benVisitDetailsRepo.saveAndFlush(existing); + } + return existing; + } Integer visitCount = benVisitDetailsRepo.countStopTBVisits(beneficiaryRegID); short visitNo = (short) ((visitCount != null ? visitCount : 0) + 1); diff --git a/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java index 99db4fcbe..1f8fa0b8c 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java @@ -13,6 +13,8 @@ import com.iemr.flw.service.CampConfigService; import com.iemr.flw.service.TBStopVisitService; import com.iemr.flw.service.TBSuspectedService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.masterEnum.StateCode; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +23,11 @@ import java.sql.Timestamp; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; @Service public class TBSuspectedServiceImpl implements TBSuspectedService { @@ -40,6 +46,9 @@ public class TBSuspectedServiceImpl implements TBSuspectedService { @Autowired private IncentiveLogicService incentiveLogicService; + @Autowired + private UserService userService; + @Override public String getByBenId(Long benId, String authorisation) throws Exception { return null; @@ -140,16 +149,115 @@ public String save(TBSuspectedRequestDTO requestDTO) throws Exception { @Override public String getByUserId(GetBenRequestHandler request) { List dtos = new ArrayList<>(); - List tbSuspectedList = request.getProviderServiceMapID() != null + boolean stopTbVillage = request.getProviderServiceMapID() != null; + List tbSuspectedList = stopTbVillage ? tbSuspectedRepo.getByProviderServiceMapIdAndVillageId(request.getProviderServiceMapID(), request.getVillageID()) : tbSuspectedRepo.getByUserId(request.getAshaId(), request.getFromDate(), request.getToDate()); + if (stopTbVillage) { + dtos = stopTbVillageDtos(tbSuspectedList); + } else { + for (TBSuspected tbSuspected : tbSuspectedList) { + TBSuspectedDTO dto = modelMapper.map(tbSuspected, TBSuspectedDTO.class); + dto.setUpdateDate(tbSuspected.getLastModDate()); + dto.setUpdatedBy(tbSuspected.getModifiedBy()); + dtos.add(dto); + + if (tbSuspected != null && Boolean.TRUE.equals(tbSuspected.getIsConfirmed())) { + incentiveLogicService.incentiveForTbSuspected( + tbSuspected.getBenId(), + tbSuspected.getVisitDate(), + tbSuspected.getVisitDate(), + tbSuspected.getUserId() + ); + } + } + } + TBSuspectedRequestDTO tbSuspectedRequestDTO = new TBSuspectedRequestDTO(); + tbSuspectedRequestDTO.setTbSuspectedList(dtos); + tbSuspectedRequestDTO.setUserId(request.getAshaId()); + Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return gson.toJson(tbSuspectedRequestDTO); + } + + // Stop TB village list (psm + village). Same DTOs and incentive calls as the per-user path, but the + // user's state is read once per user: IncentiveLogicImpl.incentiveForTbSuspected loads the full user + // detail on every call only to check for CG, and does nothing for any other state, so for other + // states the call is skipped and for CG users it is made exactly as before. + private List stopTbVillageDtos(List tbSuspectedList) { + List dtos = new ArrayList<>(); + Map stateByUser = new HashMap<>(); + Set usersWithoutDetail = new HashSet<>(); for (TBSuspected tbSuspected : tbSuspectedList) { - TBSuspectedDTO dto = modelMapper.map(tbSuspected, TBSuspectedDTO.class); + TBSuspectedDTO dto = toDto(tbSuspected); dto.setUpdateDate(tbSuspected.getLastModDate()); dto.setUpdatedBy(tbSuspected.getModifiedBy()); dtos.add(dto); - if (tbSuspected != null && Boolean.TRUE.equals(tbSuspected.getIsConfirmed())) { + if (Boolean.TRUE.equals(tbSuspected.getIsConfirmed())) { + Integer userId = tbSuspected.getUserId(); + if (!stateByUser.containsKey(userId) && !usersWithoutDetail.contains(userId)) { + try { + stateByUser.put(userId, userService.getUserDetail(userId).getStateId()); + } catch (Exception e) { + logger.error("Check Tb Suspected Incentive Exception: ", e); + usersWithoutDetail.add(userId); + } + } + Integer stateCode = stateByUser.get(userId); + if (stateCode != null && stateCode == StateCode.CG.getStateCode()) { + incentiveLogicService.incentiveForTbSuspected( + tbSuspected.getBenId(), + tbSuspected.getVisitDate(), + tbSuspected.getVisitDate(), + userId + ); + } + } + } + return dtos; + } + + // Field-by-field copy of the same-named fields ModelMapper copied (updateDate/updatedBy are set by + // the caller); ModelMapper's reflection per row was most of this list's time at village scale. + private static TBSuspectedDTO toDto(TBSuspected s) { + TBSuspectedDTO dto = new TBSuspectedDTO(); + dto.setId(s.getId()); + dto.setBenId(s.getBenId()); + dto.setVisitLabel(s.getVisitLabel()); + dto.setVisitDate(s.getVisitDate()); + dto.setTypeOfTBCase(s.getTypeOfTBCase()); + dto.setReasonForSuspicion(s.getReasonForSuspicion()); + dto.setIsSputumCollected(s.getIsSputumCollected()); + dto.setSputumSubmittedAt(s.getSputumSubmittedAt()); + dto.setNikshayId(s.getNikshayId()); + dto.setSputumTestResult(s.getSputumTestResult()); + dto.setIsChestXRayDone(s.getIsChestXRayDone()); + dto.setChestXRayResult(s.getChestXRayResult()); + dto.setReasonForRefusalXray(s.getReasonForRefusalXray()); + dto.setReasonForRefusalMTB(s.getReasonForRefusalMTB()); + dto.setReasonForRefusalMDRRIF(s.getReasonForRefusalMDRRIF()); + dto.setReasonForRefusalSputum(s.getReasonForRefusalSputum()); + dto.setMdrRifResult(s.getMdrRifResult()); + dto.setReferralFacility(s.getReferralFacility()); + dto.setIsTBConfirmed(s.getIsTBConfirmed()); + dto.setIsConfirmed(s.getIsConfirmed()); + dto.setIsDRTBConfirmed(s.getIsDRTBConfirmed()); + dto.setReferred(s.getReferred()); + dto.setFollowUps(s.getFollowUps()); + return dto; + } + + @Override + public java.util.Map getRecordsByIds(java.util.Collection ids) { + Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + java.util.Map out = new java.util.LinkedHashMap<>(); + for (TBSuspected tbSuspected : tbSuspectedRepo.findAllById(ids)) { + TBSuspectedDTO dto = modelMapper.map(tbSuspected, TBSuspectedDTO.class); + dto.setUpdateDate(tbSuspected.getLastModDate()); + dto.setUpdatedBy(tbSuspected.getModifiedBy()); + out.put(tbSuspected.getId(), gson.toJson(dto)); + // Same side effect as getByUserId, so incentives don't depend on which pull the app uses. + if (Boolean.TRUE.equals(tbSuspected.getIsConfirmed())) { incentiveLogicService.incentiveForTbSuspected( tbSuspected.getBenId(), tbSuspected.getVisitDate(), @@ -158,11 +266,7 @@ public String getByUserId(GetBenRequestHandler request) { ); } } - TBSuspectedRequestDTO tbSuspectedRequestDTO = new TBSuspectedRequestDTO(); - tbSuspectedRequestDTO.setTbSuspectedList(dtos); - tbSuspectedRequestDTO.setUserId(request.getAshaId()); - Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); - return gson.toJson(tbSuspectedRequestDTO); + return out; } } diff --git a/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java index 60ae973e7..b3fef7139 100644 --- a/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java @@ -8,6 +8,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.stream.Collectors; + @Service public class UserServiceImpl implements UserService { @@ -21,8 +28,171 @@ public class UserServiceImpl implements UserService { public UserServiceRoleDTO getUserDetail(Integer userId) { logger.info("calling getUserRole for userId: " + userId); - UserServiceRoleDTO userRole = userServiceRoleRepo.getUserRole(userId).get(0); + List roles = userServiceRoleRepo.getUserRole(userId); + if (roles == null || roles.isEmpty()) { + throw new IllegalStateException("No active role mapping for userId " + userId); + } + // A user can have several mapping rows. Taking whichever came first dropped the villages + // on the others; use the STOP-TB (Nikshay) row when there is one, and the villages of + // every row for that same service. + UserServiceRoleDTO userRole = primaryRole(userId, roles); + mergeVillages(userRole, roles); userRole.setFacilityData(facilityDataService.buildFacilityData(userId, userRole.getRoleName())); + + // Two different villages can legitimately share the same name (confirmed live: + // Nikshay village IDs 275135 and 275136 are both named "Sanapindapadar", under + // two different facilities in Boriguma block, Koraput). The mobile app's village + // dropdown displays villageName only, so a user has no way to tell which one + // they're picking - selecting the wrong one loads zero HH records for that + // village, since worklists filter by ID, not name. Append the ID into each name + // segment so duplicates are visually distinguishable. Response shape is + // unchanged - still two parallel comma-separated strings - so this needs zero + // mobile app changes: it just displays whatever text is in the name string + // (confirmed against ServiceLocationViewModel/BindingUtils.setSpinnerItems - + // plain ArrayAdapter, selection is by array position, not by name content). + userRole.setVillageName(appendVillageIds(userRole.getVillageId(), userRole.getVillageName())); + + // Stop TB / Nikshay — additive only. This naturally returns nothing for + // any user whose rows don't have NikshayTUID set, i.e. every non-Stop-TB + // user. Fetched first so the district-by-block patch below can tell + // Stop TB users apart and skip them. + List nikshayRows = userServiceRoleRepo.getNikshayMappingRows(userId, userRole.getProviderServiceMapId()); + boolean isStopTBUser = nikshayRows != null && !nikshayRows.isEmpty(); + + // Stop TB's BlockId holds a Nikshay TU ID, not an AMRIT BlockID - + // joining it against m_districtblock/m_district (what + // getDistrictByBlockId does) would resolve to whatever AMRIT + // district happens to share that same numeric ID by coincidence, + // not real data. Skip this patch for Stop TB users. + if (!isStopTBUser && userRole.getWorkingDistrictId() == null && userRole.getBlockId() != null) { + List districtResults = userServiceRoleRepo.getDistrictByBlockId(userRole.getBlockId()); + if (districtResults != null && !districtResults.isEmpty()) { + Object[] district = districtResults.get(0); + if (district != null && district.length == 2) { + userRole.setWorkingDistrictId(((Number) district[0]).intValue()); + userRole.setWorkingDistrictName((String) district[1]); + } + } + } + + if (isStopTBUser) { + TreeSet tuIds = new TreeSet<>(); + TreeSet facilityIds = new TreeSet<>(); + Integer districtId = null; + for (Object[] row : nikshayRows) { + addCsvIds((String) row[0], tuIds); + addCsvIds((String) row[1], facilityIds); + if (districtId == null && row[2] != null) { + districtId = ((Number) row[2]).intValue(); + } + } + + Map tuNames = tuIds.isEmpty() ? Map.of() + : toIdNameMap(userServiceRoleRepo.findNikshayTuNames(tuIds)); + Map facilityNames = facilityIds.isEmpty() ? Map.of() + : toIdNameMap(userServiceRoleRepo.findNikshayFacilityNames(facilityIds)); + + userRole.setTuId(joinIds(tuIds)); + userRole.setTuName(joinNames(tuIds, tuNames)); + userRole.setHealthFacilityId(joinIds(facilityIds)); + userRole.setHealthFacilityName(joinNames(facilityIds, facilityNames)); + + // Stop TB never sets WorkingLocationID, so workingDistrictId/Name + // (derived from it) are always null. DistrictID sits directly on + // the mapping row instead - Stop TB has no "work location" + // indirection layer the way other servicelines do, so read it + // straight from there rather than trying to derive it. + if (districtId != null) { + userRole.setWorkingDistrictId(districtId); + userRole.setWorkingDistrictName(userServiceRoleRepo.findNikshayDistrictName(districtId)); + } + } + return userRole; } + + private UserServiceRoleDTO primaryRole(Integer userId, List roles) { + if (roles.size() == 1) return roles.get(0); + for (UserServiceRoleDTO role : roles) { + List nikshay = userServiceRoleRepo.getNikshayMappingRows(userId, role.getProviderServiceMapId()); + if (nikshay != null && !nikshay.isEmpty()) return role; + } + return roles.get(0); + } + + // Unions the parallel villageId/villageName lists of every row for the chosen row's service, + // keeping first-seen order and one entry per village ID. Rows whose two lists don't line up + // are left out of the merge rather than risk pairing an ID with the wrong name. + private void mergeVillages(UserServiceRoleDTO userRole, List roles) { + java.util.LinkedHashMap byId = new java.util.LinkedHashMap<>(); + for (UserServiceRoleDTO role : roles) { + if (!java.util.Objects.equals(role.getProviderServiceMapId(), userRole.getProviderServiceMapId())) continue; + if (role.getVillageId() == null || role.getVillageId().isBlank() + || role.getVillageName() == null || role.getVillageName().isBlank()) continue; + String[] ids = role.getVillageId().split(",", -1); + String[] names = role.getVillageName().split(",", -1); + if (ids.length != names.length) continue; + for (int i = 0; i < ids.length; i++) { + if (!ids[i].isBlank()) byId.putIfAbsent(ids[i].trim(), names[i].trim()); + } + } + if (byId.isEmpty()) return; + userRole.setVillageId(String.join(",", byId.keySet())); + userRole.setVillageName(String.join(",", byId.values())); + } + + // Zips the parallel villageId/villageName comma lists and rejoins each pair as + // "name (id)", e.g. "Sanapindapadar,Sanapindapadar" + "275135,275136" becomes + // "Sanapindapadar (275135),Sanapindapadar (275136)". Falls back to the original, + // unmodified villageName on any shape mismatch (null/blank, or unequal segment + // counts between the two lists) rather than risk emitting a malformed string. + private String appendVillageIds(String villageId, String villageName) { + if (villageId == null || villageId.isBlank() || villageName == null || villageName.isBlank()) { + return villageName; + } + String[] ids = villageId.split(",", -1); + String[] names = villageName.split(",", -1); + if (ids.length != names.length) { + logger.warn("villageId/villageName segment count mismatch ({} vs {}); leaving villageName unmodified", + ids.length, names.length); + return villageName; + } + StringBuilder result = new StringBuilder(); + for (int i = 0; i < names.length; i++) { + if (i > 0) { + result.append(","); + } + result.append(names[i].trim()).append(" (").append(ids[i].trim()).append(")"); + } + return result.toString(); + } + + private void addCsvIds(String csv, Collection target) { + if (csv == null || csv.isBlank()) { + return; + } + for (String id : csv.split(",")) { + try { + target.add(Integer.valueOf(id.trim())); + } catch (NumberFormatException ignored) { + // skip malformed entries rather than fail the whole login + } + } + } + + private Map toIdNameMap(List rows) { + Map map = new HashMap<>(); + for (Object[] row : rows) { + map.put(((Number) row[0]).intValue(), (String) row[1]); + } + return map; + } + + private String joinIds(Collection ids) { + return ids.stream().map(String::valueOf).collect(Collectors.joining(",")); + } + + private String joinNames(Collection ids, Map names) { + return ids.stream().map(id -> names.getOrDefault(id, "")).collect(Collectors.joining(",")); + } } diff --git a/src/main/java/com/iemr/flw/service/impl/WorklistPagePrefetch.java b/src/main/java/com/iemr/flw/service/impl/WorklistPagePrefetch.java new file mode 100644 index 000000000..b34acf9a8 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/WorklistPagePrefetch.java @@ -0,0 +1,191 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.BenAnthropometryDetail; +import com.iemr.flw.domain.iemr.BenFlowStatus; +import com.iemr.flw.domain.iemr.BenPhysicalVitalDetail; +import com.iemr.flw.domain.identity.*; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.stereotype.Component; + +import java.math.BigInteger; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Loads everything the worklist builder needs for one page with one query per table, instead of + * ~16 queries per beneficiary. Each query keeps the ordering of the per-row query it replaces, so + * the response is unchanged. + * + * IDs are written into the SQL as numeric literals rather than bound as a collection: Hibernate 6.4.1 + * in this service throws "Binding is multi-valued" for every IN (:list) parameter. The values are + * Long/BigInteger read from the database, so the literal list cannot carry anything but digits. + */ +@Component +public class WorklistPagePrefetch { + + @PersistenceContext(unitName = "db_identity") + private EntityManager identityEm; + + @PersistenceContext(unitName = "db_iemr") + private EntityManager iemrEm; + + public static class Page { + final Map> mappingsByAddress = new HashMap<>(); + final Map details = new HashMap<>(); + final Map accounts = new HashMap<>(); + final Map images = new HashMap<>(); + final Map addresses = new HashMap<>(); + final Map contacts = new HashMap<>(); + final Map> benIdsByRegId = new HashMap<>(); + final Map> rmnchByRegId = new HashMap<>(); + final Map> bornBirthByRegId = new HashMap<>(); + final Map> householdsById = new HashMap<>(); + final Map> flowsByRegId = new HashMap<>(); + final Map> anthropometryByRegId = new HashMap<>(); + final Map> vitalsByRegId = new HashMap<>(); + final Set regIdsWithHealthId = new HashSet<>(); + final Map userIdByName = new HashMap<>(); + + public List mappings(BigInteger addressId) { + return mappingsByAddress.getOrDefault(addressId, Collections.emptyList()); + } + public RMNCHMBeneficiarydetail detail(BigInteger id) { return details.get(id); } + public RMNCHMBeneficiaryAccount account(BigInteger id) { return accounts.get(id); } + public RMNCHMBeneficiaryImage image(BigInteger id) { return images.get(id); } + public RMNCHMBeneficiaryaddress address(BigInteger id) { return addresses.get(id); } + public RMNCHMBeneficiarycontact contact(BigInteger id) { return contacts.get(id); } + public List benIds(Long regId) { return benIdsByRegId.getOrDefault(regId, Collections.emptyList()); } + public List rmnch(Long regId) { return rmnchByRegId.getOrDefault(regId, Collections.emptyList()); } + public List bornBirth(Long regId) { return bornBirthByRegId.getOrDefault(regId, Collections.emptyList()); } + public List households(Long householdId) { return householdsById.getOrDefault(householdId, Collections.emptyList()); } + public List flows(Long regId) { return flowsByRegId.getOrDefault(regId, Collections.emptyList()); } + public List anthropometry(Long regId) { return anthropometryByRegId.getOrDefault(regId, Collections.emptyList()); } + public List vitals(Long regId) { return vitalsByRegId.getOrDefault(regId, Collections.emptyList()); } + public boolean hasHealthId(Long regId) { return regIdsWithHealthId.contains(regId); } + public Map userIdCache() { return userIdByName; } + } + + /** The page's addresses in the order of {@code ids} (the worklist page order); ids with no row are skipped, as before. */ + public List addressesInOrder(List ids) { + Map byId = new HashMap<>(); + putAll(byId, entities(identityEm, RMNCHMBeneficiaryaddress.class, + "SELECT * FROM db_identity.i_beneficiaryaddress WHERE BenAddressID IN (%s)", + new LinkedHashSet<>(ids)), RMNCHMBeneficiaryaddress::getBenAddressID); + return ids.stream().map(byId::get).filter(Objects::nonNull).collect(Collectors.toList()); + } + + public Page load(List pageAddresses) { + Page page = new Page(); + pageAddresses.forEach(a -> page.addresses.put(a.getBenAddressID(), a)); + // The builder looks mappings up by address.getId(), which is the VanSerialNo column, not the + // address primary key - keep that exactly. + Set lookupIds = pageAddresses.stream().map(RMNCHMBeneficiaryaddress::getId) + .filter(Objects::nonNull).collect(Collectors.toCollection(LinkedHashSet::new)); + if (lookupIds.isEmpty()) return page; + + // getByAddressID: ORDER BY BenMapId DESC + for (RMNCHMBeneficiarymapping m : entities(identityEm, RMNCHMBeneficiarymapping.class, + "SELECT * FROM db_identity.i_beneficiarymapping WHERE BenAddressId IN (%s) ORDER BY BenMapId DESC", lookupIds)) { + page.mappingsByAddress.computeIfAbsent(m.getBenAddressId(), k -> new ArrayList<>()).add(m); + } + // the builder only uses the first (newest) mapping of each address + List used = page.mappingsByAddress.values().stream() + .map(l -> l.get(0)).collect(Collectors.toList()); + + putAll(page.details, entities(identityEm, RMNCHMBeneficiarydetail.class, + "SELECT * FROM db_identity.i_beneficiarydetails WHERE BeneficiaryDetailsId IN (%s)", + ids(used, RMNCHMBeneficiarymapping::getBenDetailsId)), RMNCHMBeneficiarydetail::getBeneficiaryDetailsId); + putAll(page.accounts, entities(identityEm, RMNCHMBeneficiaryAccount.class, + "SELECT * FROM db_identity.i_beneficiaryaccount WHERE BenAccountID IN (%s)", + ids(used, RMNCHMBeneficiarymapping::getBenAccountID)), RMNCHMBeneficiaryAccount::getBenAccountID); + putAll(page.images, entities(identityEm, RMNCHMBeneficiaryImage.class, + "SELECT * FROM db_identity.i_beneficiaryimage WHERE BenImageId IN (%s)", + ids(used, RMNCHMBeneficiarymapping::getBenImageId)), RMNCHMBeneficiaryImage::getBenImageId); + putAll(page.contacts, entities(identityEm, RMNCHMBeneficiarycontact.class, + "SELECT * FROM db_identity.i_beneficiarycontacts WHERE BenContactsID IN (%s)", + ids(used, RMNCHMBeneficiarymapping::getBenContactsId)), RMNCHMBeneficiarycontact::getBenContactsID); + Set missingAddressIds = ids(used, RMNCHMBeneficiarymapping::getBenAddressId); + missingAddressIds.removeAll(page.addresses.keySet()); + putAll(page.addresses, entities(identityEm, RMNCHMBeneficiaryaddress.class, + "SELECT * FROM db_identity.i_beneficiaryaddress WHERE BenAddressID IN (%s)", missingAddressIds), + RMNCHMBeneficiaryaddress::getBenAddressID); + + Set regIds = ids(used, RMNCHMBeneficiarymapping::getBenRegId); + if (regIds.isEmpty()) return page; + + for (Object[] r : rows(identityEm, + "SELECT BenRegId, BeneficiaryID FROM db_identity.m_beneficiaryregidmapping WHERE BenRegId IN (%s)", regIds)) { + page.benIdsByRegId.computeIfAbsent(toLong(r[0]), k -> new ArrayList<>()).add(toBigInteger(r[1])); + } + // getDetailsByRegID: ORDER BY beneficiaryDetails_RmnchId DESC + group(page.rmnchByRegId, entities(identityEm, RMNCHBeneficiaryDetailsRmnch.class, + "SELECT * FROM db_identity.i_beneficiarydetails_rmnch WHERE BeneficiaryRegID IN (%s) ORDER BY beneficiaryDetails_RmnchId DESC", + regIds), RMNCHBeneficiaryDetailsRmnch::getBenRegId); + group(page.bornBirthByRegId, entities(identityEm, RMNCHBornBirthDetails.class, + "SELECT * FROM db_identity.i_bornbirthdeatils WHERE BeneficiaryRegID IN (%s) ORDER BY BornBirthDeatilsId", + regIds), RMNCHBornBirthDetails::getBenRegId); + + // households of the newest rmnch row (the one the builder uses) + Set householdIds = page.rmnchByRegId.values().stream().map(l -> l.get(0).getHouseoldId()) + .filter(Objects::nonNull).collect(Collectors.toCollection(LinkedHashSet::new)); + group(page.householdsById, entities(identityEm, RMNCHHouseHoldDetails.class, + "SELECT * FROM db_identity.i_householddetails WHERE houseoldId IN (%s) ORDER BY houseHoldDetailsId", + householdIds), RMNCHHouseHoldDetails::getHouseoldId); + + group(page.flowsByRegId, entities(iemrEm, BenFlowStatus.class, + "SELECT * FROM db_iemr.i_ben_flow_outreach WHERE beneficiary_reg_id IN (%s) ORDER BY ben_flow_id", + regIds), BenFlowStatus::getBeneficiaryRegID); + // findByBeneficiaryRegIDOrderByCreatedDateDesc + group(page.anthropometryByRegId, entities(iemrEm, BenAnthropometryDetail.class, + "SELECT * FROM db_iemr.t_phy_anthropometry WHERE BeneficiaryRegID IN (%s) ORDER BY CreatedDate DESC", + regIds), BenAnthropometryDetail::getBeneficiaryRegID); + group(page.vitalsByRegId, entities(iemrEm, BenPhysicalVitalDetail.class, + "SELECT * FROM db_iemr.t_phy_vitals WHERE BeneficiaryRegID IN (%s) ORDER BY CreatedDate DESC", + regIds), BenPhysicalVitalDetail::getBeneficiaryRegID); + + for (Object id : iemrEm.createNativeQuery(String.format( + "SELECT DISTINCT BeneficiaryRegID FROM db_iemr.m_benhealthidmapping WHERE BeneficiaryRegID IN (%s)", + literalList(regIds))).getResultList()) { + page.regIdsWithHealthId.add(toLong(id)); + } + return page; + } + + @SuppressWarnings("unchecked") + private static List entities(EntityManager em, Class type, String sql, Collection ids) { + if (ids.isEmpty()) return Collections.emptyList(); + return em.createNativeQuery(String.format(sql, literalList(ids)), type).getResultList(); + } + + @SuppressWarnings("unchecked") + private static List rows(EntityManager em, String sql, Collection ids) { + if (ids.isEmpty()) return Collections.emptyList(); + return em.createNativeQuery(String.format(sql, literalList(ids))).getResultList(); + } + + private static Set ids(List rows, Function getter) { + return rows.stream().map(getter).filter(Objects::nonNull).collect(Collectors.toCollection(LinkedHashSet::new)); + } + + private static void putAll(Map target, List rows, Function key) { + rows.forEach(r -> target.putIfAbsent(key.apply(r), r)); + } + + private static void group(Map> target, List rows, Function key) { + rows.forEach(r -> target.computeIfAbsent(key.apply(r), k -> new ArrayList<>()).add(r)); + } + + // Only whole numbers ever reach the SQL text: anything else is rejected rather than quoted. + private static String literalList(Collection ids) { + return ids.stream().map(id -> { + if (id instanceof Number) return new BigInteger(id.toString()).toString(); + throw new IllegalArgumentException("Non-numeric id in worklist prefetch: " + id); + }).collect(Collectors.joining(",")); + } + + private static Long toLong(Object o) { return o == null ? null : ((Number) o).longValue(); } + + private static BigInteger toBigInteger(Object o) { return o == null ? null : new BigInteger(o.toString()); } +} diff --git a/src/main/java/com/iemr/flw/service/sync/StopTBSyncType.java b/src/main/java/com/iemr/flw/service/sync/StopTBSyncType.java new file mode 100644 index 000000000..8ac1db509 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/sync/StopTBSyncType.java @@ -0,0 +1,151 @@ +package com.iemr.flw.service.sync; + +import java.util.List; + +/** + * The record types the STOP-TB changes feed (/stoptb/sync/changes) serves, in snapshot order + * (beneficiaries first, so a tablet has the person before their TB records). + * + * For each type: + * - {@code logEntity}: the entity name the hub's change-log triggers write (AMRIT-DB + * dbiemr/V132__Sync_Change_Log.sql and dbidentity/V32__Sync_Change_Log_Beneficiary.sql); + * - {@code snapshotKeySql}: the keys in scope, for the first full download, with the same filters + * the type's getAll endpoint applies. Parameters: :psm, :villages, :after, :limit; + * - {@code sourceTables}: every table the type's record is built from. Each must have the change-log + * triggers, or edits to it would never reach tablets. The feed checks this on the hub + * ({@code StopTBSyncServiceImpl#isSupported}) and a unit test checks every mapped table is either + * here or deliberately not synced. + * + * @author Piramal Swasthya + */ +public enum StopTBSyncType { + + BENEFICIARY("beneficiary", "beneficiary", + "SELECT DISTINCT f.beneficiary_reg_id FROM db_iemr.i_ben_flow_outreach f " + + "WHERE f.providerServiceMapID = :psm AND f.villageID IN (:villages) AND f.deleted = 0 " + + "AND f.beneficiary_reg_id > :after ORDER BY f.beneficiary_reg_id LIMIT :limit", + List.of("db_identity.i_beneficiarymapping", "db_identity.i_beneficiarydetails", + "db_identity.i_beneficiarydetails_rmnch", "db_identity.i_bornbirthdeatils", + "db_identity.i_beneficiaryaddress", "db_identity.i_beneficiarycontacts", + "db_identity.i_beneficiaryimage", "db_identity.i_beneficiaryaccount", + "db_identity.i_householddetails", "db_iemr.t_phy_anthropometry", "db_iemr.t_phy_vitals", + "db_iemr.i_ben_flow_outreach")), + + TB_SCREENING("tbScreening", "tb_screening", + "SELECT s.id FROM db_iemr.tb_screening s WHERE (s.deleted = 0 OR s.deleted IS NULL) " + + "AND s.ben_reg_id IN (" + Scope.REG + ") AND s.id > :after ORDER BY s.id LIMIT :limit", + List.of("db_iemr.tb_screening")), + + GENERAL_EXAMINATION("generalExamination", "general_examination", + "SELECT e.id FROM db_iemr.tb_stoptb_general_examination e WHERE e.deleted = 0 " + + "AND e.beneficiary_reg_id IN (" + Scope.REG + ") AND e.id > :after ORDER BY e.id LIMIT :limit", + List.of("db_iemr.tb_stoptb_general_examination")), + + /** OPD visits saved to the standard tables, keyed by BenVisitID. */ + GENERAL_OPD("generalOpd", "opd_visit", + "SELECT v.BenVisitID FROM db_iemr.t_benvisitdetail v WHERE v.Deleted = 0 AND v.ProviderServiceMapID = :psm " + + "AND v.BeneficiaryRegID IN (" + Scope.REG + ") AND v.BenVisitID > :after ORDER BY v.BenVisitID LIMIT :limit", + // t_prescription holds the visit's note (latest prescription instruction) + List.of("db_iemr.t_benvisitdetail", "db_iemr.t_benchiefcomplaint", "db_iemr.t_prescribeddrug", + "db_iemr.t_prescription")), + + /** Older free-text OPD rows; same record shape as GENERAL_OPD. */ + GENERAL_OPD_LEGACY("generalOpdLegacy", "general_opd", + "SELECT o.id FROM db_iemr.tb_stoptb_general_opd o WHERE o.deleted = 0 " + + "AND o.ben_reg_id IN (" + Scope.REG + ") AND o.id > :after ORDER BY o.id LIMIT :limit", + List.of("db_iemr.tb_stoptb_general_opd")), + + DIAGNOSTICS("diagnostics", "diagnostics", + "SELECT d.id FROM db_iemr.tb_stoptb_diagnostics d WHERE d.deleted = 0 " + + "AND d.ben_reg_id IN (" + Scope.REG + ") AND d.id > :after ORDER BY d.id LIMIT :limit", + List.of("db_iemr.tb_stoptb_diagnostics")), + + TB_SUSPECTED("tbSuspected", "tb_suspected", + "SELECT t.id FROM db_iemr.tb_suspected t WHERE t.ben_id IN (" + Scope.BEN_ID + ") " + + "AND t.id > :after ORDER BY t.id LIMIT :limit", + List.of("db_iemr.tb_suspected")), + + TB_CONFIRMED("tbConfirmed", "tb_confirmed", + "SELECT c.id FROM db_iemr.tb_confirmed_cases c WHERE c.ben_id IN (" + Scope.BEN_ID + ") " + + "AND c.id > :after ORDER BY c.id LIMIT :limit", + List.of("db_iemr.tb_confirmed_cases")), + + FORM_RESPONSE("formResponse", "form_response", + "SELECT r.responseId FROM db_iemr.t_form_response r WHERE r.beneficiaryId IN (" + Scope.BEN_ID_NOT_DELETED + ") " + + "AND r.responseId > :after ORDER BY r.responseId LIMIT :limit", + List.of("db_iemr.t_form_response", "db_iemr.t_section_response", "db_iemr.t_question_response")), + + DIAGNOSTIC_ORDER("diagnosticOrder", "diagnostic_order", + "SELECT o.id FROM db_iemr.tb_diagnostic_order o WHERE o.deleted = 0 " + + "AND o.beneficiary_id IN (" + Scope.BEN_ID_NOT_DELETED + ") AND o.id > :after ORDER BY o.id LIMIT :limit", + List.of("db_iemr.tb_diagnostic_order", "db_iemr.tb_diagnostic_result")); + + /** Beneficiaries in the requested villages, the same way today's getAll endpoints scope. */ + static final class Scope { + static final String REG = "SELECT f.beneficiary_reg_id FROM db_iemr.i_ben_flow_outreach f " + + "WHERE f.providerServiceMapID = :psm AND f.villageID IN (:villages)"; + static final String BEN_ID = "SELECT f.beneficiary_id FROM db_iemr.i_ben_flow_outreach f " + + "WHERE f.providerServiceMapID = :psm AND f.villageID IN (:villages)"; + static final String BEN_ID_NOT_DELETED = BEN_ID + " AND f.deleted = 0"; + // The same, for specific beneficiaries (by BenRegId) that just came into scope. + static final String REG_FOR_BENS = "SELECT f.beneficiary_reg_id FROM db_iemr.i_ben_flow_outreach f " + + "WHERE f.beneficiary_reg_id IN (:regIds)"; + static final String BEN_ID_FOR_BENS = "SELECT f.beneficiary_id FROM db_iemr.i_ben_flow_outreach f " + + "WHERE f.beneficiary_reg_id IN (:regIds)"; + + private Scope() { + } + } + + private final String apiName; + private final String logEntity; + private final String snapshotKeySql; + private final String keysForBeneficiariesSql; + private final List sourceTables; + + StopTBSyncType(String apiName, String logEntity, String snapshotKeySql, List sourceTables) { + this.apiName = apiName; + this.logEntity = logEntity; + this.snapshotKeySql = snapshotKeySql; + // The snapshot query with its village scope swapped for "these beneficiaries" and its keyset + // paging dropped. Parameters: :regIds (and :psm where the snapshot filters on it). + this.keysForBeneficiariesSql = snapshotKeySql + .replace(Scope.BEN_ID_NOT_DELETED, Scope.BEN_ID_FOR_BENS) + .replace(Scope.BEN_ID, Scope.BEN_ID_FOR_BENS) + .replace(Scope.REG, Scope.REG_FOR_BENS) + .replaceAll(" AND \\S+ > :after ORDER BY \\S+ LIMIT :limit$", ""); + this.sourceTables = sourceTables; + } + + /** The "type" field of an item in the feed. */ + public String apiName() { + return apiName; + } + + public String logEntity() { + return logEntity; + } + + public String snapshotKeySql() { + return snapshotKeySql; + } + + /** + * Keys of this type's records for beneficiaries that just came into a tablet's scope, so their + * older records (logged before they were in scope) still reach it. Not used for BENEFICIARY. + */ + public String keysForBeneficiariesSql() { + return keysForBeneficiariesSql; + } + + public List sourceTables() { + return sourceTables; + } + + public static StopTBSyncType fromLogEntity(String entity) { + for (StopTBSyncType t : values()) { + if (t.logEntity.equals(entity)) return t; + } + return null; + } +} diff --git a/src/main/java/com/iemr/flw/service/sync/SyncToken.java b/src/main/java/com/iemr/flw/service/sync/SyncToken.java new file mode 100644 index 000000000..0055b0247 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/sync/SyncToken.java @@ -0,0 +1,117 @@ +package com.iemr.flw.service.sync; + +/** + * The tablet's opaque sync position. Two kinds: + * + * d.<serverId>.<seq>.<issuedEpochSeconds>.<typesMask>.<scopeHash> + * changes after change-log line seq on this hub; + * s.<serverId>.<snapshotSeq>.<typeIndex>.<afterKey>.<typesMask>.<scopeHash> + * part-way through a first download: the next page starts at type typeIndex, after afterKey, + * and when it finishes the tablet continues with changes after snapshotSeq. + * + * serverId is the hub's MySQL server_uuid, so a token from another hub is never trusted. The issue + * time lets the hub tell when the log lines a token points after may have been cleaned up. + * typesMask is the set of record types the token was issued for (bit = StopTBSyncType ordinal): a + * token only covers those types, so a request for a different set starts a new snapshot. scopeHash + * is the service and village list the token was issued for (UserSyncScope.scopeHash); a different + * scope also starts a new snapshot. + * + * @author Piramal Swasthya + */ +public final class SyncToken { + + public enum Kind { DELTA, SNAPSHOT } + + private final Kind kind; + private final String serverId; + private final long seq; + private final long issuedAt; + private final int typeIndex; + private final long afterKey; + private final long typesMask; + private final long scopeHash; + + private SyncToken(Kind kind, String serverId, long seq, long issuedAt, int typeIndex, long afterKey, + long typesMask, long scopeHash) { + this.kind = kind; + this.serverId = serverId; + this.seq = seq; + this.issuedAt = issuedAt; + this.typeIndex = typeIndex; + this.afterKey = afterKey; + this.typesMask = typesMask; + this.scopeHash = scopeHash; + } + + public static SyncToken delta(String serverId, long seq, long issuedAt, long typesMask, long scopeHash) { + return new SyncToken(Kind.DELTA, serverId, seq, issuedAt, 0, 0, typesMask, scopeHash); + } + + public static SyncToken snapshot(String serverId, long snapshotSeq, int typeIndex, long afterKey, long typesMask, + long scopeHash) { + return new SyncToken(Kind.SNAPSHOT, serverId, snapshotSeq, 0, typeIndex, afterKey, typesMask, scopeHash); + } + + /** null for a missing or unreadable token; the caller then starts a snapshot. */ + public static SyncToken parse(String token) { + if (token == null || token.isBlank()) return null; + String[] p = token.trim().split("\\."); + try { + if (p.length == 6 && "d".equals(p[0]) && !p[1].isEmpty()) { + return delta(p[1], Long.parseLong(p[2]), Long.parseLong(p[3]), Long.parseLong(p[4]), + Long.parseLong(p[5])); + } + if (p.length == 7 && "s".equals(p[0]) && !p[1].isEmpty()) { + return snapshot(p[1], Long.parseLong(p[2]), Integer.parseInt(p[3]), Long.parseLong(p[4]), + Long.parseLong(p[5]), Long.parseLong(p[6])); + } + } catch (NumberFormatException e) { + return null; + } + return null; + } + + public String encode() { + return kind == Kind.DELTA + ? "d." + serverId + "." + seq + "." + issuedAt + "." + typesMask + "." + scopeHash + : "s." + serverId + "." + seq + "." + typeIndex + "." + afterKey + "." + typesMask + "." + scopeHash; + } + + public Kind kind() { + return kind; + } + + public String serverId() { + return serverId; + } + + /** DELTA: last change-log line applied. SNAPSHOT: the line changes continue from afterwards. */ + public long seq() { + return seq; + } + + public long issuedAt() { + return issuedAt; + } + + public int typeIndex() { + return typeIndex; + } + + public long afterKey() { + return afterKey; + } + + public long typesMask() { + return typesMask; + } + + public long scopeHash() { + return scopeHash; + } + + @Override + public String toString() { + return encode(); + } +} diff --git a/src/main/java/com/iemr/flw/service/sync/UserSyncScope.java b/src/main/java/com/iemr/flw/service/sync/UserSyncScope.java new file mode 100644 index 000000000..0573daf04 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/sync/UserSyncScope.java @@ -0,0 +1,66 @@ +package com.iemr.flw.service.sync; + +import java.util.*; + +/** + * The villages a user may sync, per provider service map: every active role-mapping row counts + * (a user can have several), each holding a comma-separated village list. + * + * @author Piramal Swasthya + */ +public final class UserSyncScope { + + private final Map> villagesByService; + + private UserSyncScope(Map> villagesByService) { + this.villagesByService = villagesByService; + } + + /** rows: [ProviderServiceMapID, Villageid csv] from m_userservicerolemapping. */ + public static UserSyncScope fromMappingRows(List rows) { + Map> out = new HashMap<>(); + for (Object[] row : rows) { + if (row == null || row[0] == null) continue; + Set villages = out.computeIfAbsent(((Number) row[0]).intValue(), k -> new TreeSet<>()); + if (row.length > 1 && row[1] != null) { + for (String id : row[1].toString().split(",")) { + try { + villages.add(Integer.valueOf(id.trim())); + } catch (NumberFormatException ignored) { + // malformed entry: not a village the user can sync + } + } + } + } + return new UserSyncScope(out); + } + + /** + * The villages to sync for this request: all of the user's villages for the service when none + * are asked for, otherwise exactly the ones asked for. Throws when the service or any village + * isn't mapped to the user. + */ + public List resolve(Integer providerServiceMapID, List requested) { + Set allowed = villagesByService.get(providerServiceMapID); + if (allowed == null) { + throw new IllegalArgumentException("User is not mapped to providerServiceMapID " + providerServiceMapID); + } + if (requested == null || requested.isEmpty()) { + if (allowed.isEmpty()) throw new IllegalArgumentException("User has no villages for this service"); + return new ArrayList<>(allowed); + } + List outside = new ArrayList<>(); + for (Integer v : requested) if (!allowed.contains(v)) outside.add(v); + if (!outside.isEmpty()) { + throw new IllegalArgumentException("Villages not assigned to the user: " + outside); + } + return new ArrayList<>(new TreeSet<>(requested)); + } + + /** A stable fingerprint of a service and its village list, bound into sync tokens. */ + public static long scopeHash(Integer providerServiceMapID, List villages) { + List sorted = new ArrayList<>(villages); + Collections.sort(sorted); + return Integer.toUnsignedLong((providerServiceMapID + "|" + sorted).hashCode()); + } +} diff --git a/src/main/java/com/iemr/flw/utils/ApiTimingFilter.java b/src/main/java/com/iemr/flw/utils/ApiTimingFilter.java new file mode 100644 index 000000000..d93159634 --- /dev/null +++ b/src/main/java/com/iemr/flw/utils/ApiTimingFilter.java @@ -0,0 +1,40 @@ +package com.iemr.flw.utils; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +// One [API-TIMING] line per request (method, path, status, total ms incl. auth filters) so camp-laptop +// logs show every API's time: journalctl -u amrit-flw-api | grep API-TIMING +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class ApiTimingFilter implements Filter { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) + throws IOException, ServletException { + + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + long start = System.currentTimeMillis(); + try { + chain.doFilter(servletRequest, servletResponse); + } finally { + logger.info("[API-TIMING] {} {} status={} ms={}", request.getMethod(), request.getRequestURI(), + response.getStatus(), System.currentTimeMillis() - start); + } + } +} diff --git a/src/main/java/com/iemr/flw/utils/response/OutputResponse.java b/src/main/java/com/iemr/flw/utils/response/OutputResponse.java index d4cb36705..7b5f7f8e3 100644 --- a/src/main/java/com/iemr/flw/utils/response/OutputResponse.java +++ b/src/main/java/com/iemr/flw/utils/response/OutputResponse.java @@ -83,6 +83,15 @@ public void setResponse(String message) { } + // Same result as setResponse(gson.toJson(x)) for an object/array, without writing the JSON text + // and parsing it back: pass gson.toJsonTree(x). + public void setResponse(JsonElement tree) { + this.data = tree; + statusCode = SUCCESS; + errorMessage = "Success"; + status = "Success"; + } + public void setError(Throwable thrown) { Date currDate = Calendar.getInstance().getTime(); logger.info("error happened due to " + thrown.getClass().getSimpleName() + " at " + currDate.toString()); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2ffd6d6b8..e03faaa00 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -35,7 +35,7 @@ spring.datasource.tomcat.remove-abandoned=true spring.datasource.tomcat.logAbandoned=true spring.datasource.continue-on-error=true spring.datasource.tomcat.remove-abandoned-timeout=600 -door-to-door-page-size=10 +door-to-door-page-size=50 #Get-HRP-Status get-HRP-Status=ANC/getHRPStatus diff --git a/src/test/java/com/iemr/flw/service/sync/StopTBSyncCoverageTest.java b/src/test/java/com/iemr/flw/service/sync/StopTBSyncCoverageTest.java new file mode 100644 index 000000000..dea113d81 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/sync/StopTBSyncCoverageTest.java @@ -0,0 +1,106 @@ +package com.iemr.flw.service.sync; + +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Every table FLW-API maps must be either synced to STOP-TB tablets through the change log + * (listed in a {@link StopTBSyncType}'s sourceTables, which the hub checks for triggers) or listed + * below as deliberately not synced. A new entity fails this test until someone decides which, so a + * STOP-TB table can't be added without its change-log triggers. + */ +class StopTBSyncCoverageTest { + + /** STOP-TB-adjacent tables that the app does not pull, with the reason. */ + static final Map NOT_SYNCED_STOPTB = Map.ofEntries( + Map.entry("db_iemr.t_phy_generalexam", "copy of the general examination for the standard tables; the app pulls tb_stoptb_general_examination"), + Map.entry("db_iemr.t_benreferdetails", "copy written on save for the standard tables; not read by any STOP-TB pull"), + Map.entry("db_iemr.tb_stoptb_registration", "not read by any service"), + Map.entry("db_iemr.tb_diagnostic_document", "the app does not pull documents"), + Map.entry("db_iemr.tb_diagnostic_provider_token", "vendor credentials, server only"), + Map.entry("db_identity.m_beneficiaryregidmapping", "BenRegId/BeneficiaryID pool, fixed once assigned"), + Map.entry("db_iemr.t_dynamic_form", "form definitions: master data, pulled separately"), + Map.entry("db_iemr.t_form_version", "form definitions: master data, pulled separately"), + Map.entry("db_iemr.t_form_section", "form definitions: master data, pulled separately"), + Map.entry("db_iemr.t_section_question", "form definitions: master data, pulled separately"), + Map.entry("db_iemr.t_question_option", "form definitions: master data, pulled separately"), + Map.entry("db_iemr.t_question_validation", "form definitions: master data, pulled separately"), + Map.entry("db_iemr.t_option_condition", "form definitions: master data, pulled separately"), + Map.entry("db_iemr.t_dynamic_form_migration_log", "server-side bookkeeping"), + Map.entry("db_iemr.m_user", "user master, read at login"), + Map.entry("db_iemr.v_userservicerolemapping", "view of user roles, read at login"), + Map.entry("db_iemr.general_opd_entry", "not part of the STOP-TB pull")); + + /** Tables of other FLW programmes (ASHA app), not used by STOP-TB. */ + static final Set OTHER_PROGRAMMES = Set.of( + "db_iemr.adolescent_health", "db_iemr.ahd_form", "db_iemr.anc_counselling_care", "db_iemr.asha_profile", + "db_iemr.asha_supervisor_mapping", "db_iemr.campaign_filariasis_mda", "db_iemr.campaign_ors", + "db_iemr.campaign_pulse_polio", "db_iemr.cdtf_visit_details", "db_iemr.deworming_form", + "db_iemr.eligible_couple_tracking", "db_iemr.high_risk_assess", "db_iemr.i_mobilization_mosquito_net", + "db_iemr.incentive_activity_record", "db_iemr.incentive_pending_activity", "db_iemr.irs_round", + "db_iemr.leprosy_follow_up", "db_iemr.m_immunizationservicevaccination", "db_iemr.m_incentive_activity", + "db_iemr.m_incentive_activity_lang_mapping", "db_iemr.m_otp_beneficiary", "db_iemr.m_smstemplate", + "db_iemr.maa_meeting", "db_iemr.malaria_follow_up", "db_iemr.non_pregnant_high_risk_assess", + "db_iemr.non_pregnant_high_risk_track", "db_iemr.phc_review_meeting", "db_iemr.pregnant_high_risk_assess", + "db_iemr.pregnant_high_risk_track", "db_iemr.sammelan_attachment", "db_iemr.sammelan_record", "db_iemr.screening_aesje", + "db_iemr.screening_filaria", "db_iemr.screening_kala_azar", "db_iemr.screening_leprosy", + "db_iemr.screening_malaria", "db_iemr.t_anc_visit", "db_iemr.t_anccare", "db_iemr.t_cbacdetails", + "db_iemr.t_cdr", "db_iemr.t_child_register", "db_iemr.t_childvaccinedetail1", "db_iemr.t_delivery_outcome", + "db_iemr.t_eligible_couple_register", "db_iemr.t_eye_checkup", "db_iemr.t_hbnc_part1", "db_iemr.t_hbnc_part2", + "db_iemr.t_hbnc_visit", "db_iemr.t_hbnc_visit_card", "db_iemr.t_hbyc", "db_iemr.t_hbyc_child_visits", + "db_iemr.t_ifa_distribution", "db_iemr.t_ifa_distribution_data", "db_iemr.t_infant_register", + "db_iemr.t_mda_distribution_data", "db_iemr.t_mdsr", "db_iemr.t_micro_birth_plan", "db_iemr.t_ors_distribution", + "db_iemr.t_pmsma", "db_iemr.t_pnc_visit", "db_iemr.t_pnccare", "db_iemr.t_pregnant_woman_register", + "db_iemr.t_sam_visit", "db_iemr.uwin_session_record", "db_iemr.vhnc_form", "db_iemr.vhnd_form", + "db_identity.i_cbac_additional_details", "db_identity.i_cbacdetails"); + + @Test + void everyMappedTableIsSyncedOrDeliberatelyNot() throws Exception { + Set synced = new HashSet<>(); + for (StopTBSyncType t : StopTBSyncType.values()) synced.addAll(t.sourceTables()); + + List unclassified = new ArrayList<>(); + for (String table : mappedTables()) { + if (!synced.contains(table) && !NOT_SYNCED_STOPTB.containsKey(table) && !OTHER_PROGRAMMES.contains(table)) { + unclassified.add(table); + } + } + Collections.sort(unclassified); + assertTrue(unclassified.isEmpty(), "Tables neither synced to STOP-TB tablets nor listed as not synced: " + + unclassified + ". If the STOP-TB app reads it, add it to a StopTBSyncType's sourceTables and add " + + "change-log triggers in a new AMRIT-DB migration; otherwise list it here with a reason."); + } + + @Test + void syncedTablesAreNotAlsoListedAsNotSynced() { + for (StopTBSyncType t : StopTBSyncType.values()) { + for (String table : t.sourceTables()) { + assertTrue(!NOT_SYNCED_STOPTB.containsKey(table) && !OTHER_PROGRAMMES.contains(table), table); + } + } + } + + /** schema.table for every @Entity under com.iemr.flw.domain, lower-case. */ + static Set mappedTables() throws ClassNotFoundException { + ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class)); + Set tables = new TreeSet<>(); + for (BeanDefinition bd : scanner.findCandidateComponents("com.iemr.flw.domain")) { + Class c = Class.forName(bd.getBeanClassName()); + Table t = c.getAnnotation(Table.class); + String name = t != null && !t.name().isEmpty() ? t.name() : c.getSimpleName(); + String schema = t != null && !t.schema().isEmpty() ? t.schema() + : c.getPackageName().endsWith(".identity") ? "db_identity" : "db_iemr"; + tables.add((schema + "." + name).toLowerCase(Locale.ROOT)); + } + return tables; + } +} diff --git a/src/test/java/com/iemr/flw/service/sync/StopTBSyncTypeTest.java b/src/test/java/com/iemr/flw/service/sync/StopTBSyncTypeTest.java new file mode 100644 index 000000000..a7fa90e80 --- /dev/null +++ b/src/test/java/com/iemr/flw/service/sync/StopTBSyncTypeTest.java @@ -0,0 +1,21 @@ +package com.iemr.flw.service.sync; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class StopTBSyncTypeTest { + + @Test + void childKeyQueriesTargetTheGivenBeneficiariesWithoutPaging() { + for (StopTBSyncType t : StopTBSyncType.values()) { + if (t == StopTBSyncType.BENEFICIARY) continue; + String sql = t.keysForBeneficiariesSql(); + assertTrue(sql.contains(":regIds"), t + ": " + sql); + assertFalse(sql.contains(":after"), t + ": " + sql); + assertFalse(sql.contains(":limit"), t + ": " + sql); + assertFalse(sql.contains(":villages"), t + ": " + sql); + System.out.println(t + " | " + sql); + } + } +} diff --git a/src/test/java/com/iemr/flw/service/sync/SyncTokenTest.java b/src/test/java/com/iemr/flw/service/sync/SyncTokenTest.java new file mode 100644 index 000000000..3f247605b --- /dev/null +++ b/src/test/java/com/iemr/flw/service/sync/SyncTokenTest.java @@ -0,0 +1,51 @@ +package com.iemr.flw.service.sync; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class SyncTokenTest { + + private static final String UUID = "3f2a6c1e-1b2c-11ef-9f1a-0242ac120002"; + + @Test + void deltaRoundTrips() { + SyncToken t = SyncToken.parse(SyncToken.delta(UUID, 1000, 1761700000L, 0b101, 42L).encode()); + assertEquals(SyncToken.Kind.DELTA, t.kind()); + assertEquals(UUID, t.serverId()); + assertEquals(1000, t.seq()); + assertEquals(1761700000L, t.issuedAt()); + assertEquals(0b101, t.typesMask()); + assertEquals(42L, t.scopeHash()); + } + + @Test + void snapshotRoundTrips() { + SyncToken t = SyncToken.parse(SyncToken.snapshot(UUID, 5230, 3, 900, 7, 99L).encode()); + assertEquals(SyncToken.Kind.SNAPSHOT, t.kind()); + assertEquals(5230, t.seq()); + assertEquals(3, t.typeIndex()); + assertEquals(900, t.afterKey()); + assertEquals(7, t.typesMask()); + assertEquals(99L, t.scopeHash()); + } + + @Test + void unreadableTokensMeanStartOver() { + assertNull(SyncToken.parse(null)); + assertNull(SyncToken.parse("")); + assertNull(SyncToken.parse("garbage")); + assertNull(SyncToken.parse("d." + UUID + ".x.1.1.1")); + assertNull(SyncToken.parse("d." + UUID + ".1.1.1")); // no scope: issued before scope was bound + assertNull(SyncToken.parse("d..1.1.1.1")); + assertNull(SyncToken.parse("q." + UUID + ".1.1")); + } + + @Test + void everyLogEntityMapsToOneType() { + for (StopTBSyncType t : StopTBSyncType.values()) { + assertSame(t, StopTBSyncType.fromLogEntity(t.logEntity())); + } + assertNull(StopTBSyncType.fromLogEntity("unknown")); + } +} diff --git a/src/test/java/com/iemr/flw/service/sync/UserSyncScopeTest.java b/src/test/java/com/iemr/flw/service/sync/UserSyncScopeTest.java new file mode 100644 index 000000000..1398bbbdf --- /dev/null +++ b/src/test/java/com/iemr/flw/service/sync/UserSyncScopeTest.java @@ -0,0 +1,42 @@ +package com.iemr.flw.service.sync; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class UserSyncScopeTest { + + // Two mapping rows for service 1738 (villages merge), one for 1744, and a malformed entry. + private final UserSyncScope scope = UserSyncScope.fromMappingRows(List.of( + new Object[]{1738, "5443, 5444"}, + new Object[]{1738, "5445,x"}, + new Object[]{1744, "6677"}, + new Object[]{1750, null})); + + @Test + void noVillagesAskedForMeansAllOfTheUsersVillagesForThatService() { + assertEquals(List.of(5443, 5444, 5445), scope.resolve(1738, List.of())); + assertEquals(List.of(6677), scope.resolve(1744, null)); + } + + @Test + void askedForVillagesMustAllBeAssigned() { + assertEquals(List.of(5443, 5445), scope.resolve(1738, List.of(5445, 5443, 5445))); + assertThrows(IllegalArgumentException.class, () -> scope.resolve(1738, List.of(5443, 6677))); + } + + @Test + void unmappedServiceOrServiceWithoutVillagesIsRejected() { + assertThrows(IllegalArgumentException.class, () -> scope.resolve(9999, List.of())); + assertThrows(IllegalArgumentException.class, () -> scope.resolve(1750, List.of())); + } + + @Test + void scopeHashIgnoresVillageOrderButNotContent() { + assertEquals(UserSyncScope.scopeHash(1738, List.of(5443, 5444)), UserSyncScope.scopeHash(1738, List.of(5444, 5443))); + assertNotEquals(UserSyncScope.scopeHash(1738, List.of(5443)), UserSyncScope.scopeHash(1738, List.of(5443, 5444))); + assertNotEquals(UserSyncScope.scopeHash(1738, List.of(5443)), UserSyncScope.scopeHash(1744, List.of(5443))); + } +}