From db1c562f7970331f8be1f25c71a056e4ed40e27a Mon Sep 17 00:00:00 2001 From: Amoghavarsh <93114621+5Amogh@users.noreply.github.com> Date: Thu, 25 Sep 2025 11:54:58 +0530 Subject: [PATCH 01/42] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dee19366..3cf9dfcc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.iemr.common.identity identity-api - 3.1.0 + 3.8.0 war From 6bdd82251233e391a564a115d467c1e710b84bd7 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 18 Mar 2026 14:08:49 +0530 Subject: [PATCH 02/42] add status of women --- .../rmnch/RMNCHMobileAppController.java | 20 +++++++ .../rmnch/RmnchDataSyncServiceImpl.java | 58 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java index 26b2694c..d9bec043 100644 --- a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java +++ b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java @@ -72,6 +72,26 @@ public String syncDataToAmrit(@RequestBody String requestOBJ) { } + @PostMapping(value = "/syncDataToAmritByHwc", consumes = "application/json", produces = "application/json") + @Operation(summary = "Sync data to AMRIT for already regestered beneficiary with AMRIT beneficiary id ") + public String syncDataToAmritHwc(@RequestBody String requestOBJ) { + OutputResponse response = new OutputResponse(); + try { + if (requestOBJ != null) { + String s = rmnchDataSyncService.syncDataToAmrit(requestOBJ); + response.setResponse(s); + } else + response.setError(5000, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in RMNCH mobile data sync : {} " , e.getMessage()); + response.setError(5000, "Error in RMNCH mobile data sync : " + e); + } + return response.toString(); + + } + + + // @Deprecated @PostMapping(value = "/getBeneficiaryDataForVillage", consumes = "application/json", produces = "application/json") @Operation(summary = "Get beneficiary data for given village ") diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index bd973193..5b7bb79d 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -267,6 +267,64 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { return new Gson().toJson(resultMap); } + + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) + public void saveBeneficiaryDetailsAfterRegistration( + Long beneficiaryID, + Long beneficiaryRegID, + String comingRequest) { + try { + JsonObject requestObj = new Gson().fromJson(comingRequest, JsonObject.class); + + RMNCHBeneficiaryDetailsRmnch beneficiaryDetailsRmnch = + rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)); + + if (beneficiaryDetailsRmnch == null) { + beneficiaryDetailsRmnch = new RMNCHBeneficiaryDetailsRmnch(); + } + + beneficiaryDetailsRmnch.setBenficieryid(BigInteger.valueOf(beneficiaryID)); + beneficiaryDetailsRmnch.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); + beneficiaryDetailsRmnch.setCreatedBy( + requestObj.get("createdBy").getAsString()); + beneficiaryDetailsRmnch.setVanID( + requestObj.get("vanID").getAsInt()); + beneficiaryDetailsRmnch.setParkingPlaceID( + requestObj.get("parkingPlaceID").getAsInt()); + beneficiaryDetailsRmnch.setProviderServiceMapID( + requestObj.get("providerServiceMapID").getAsInt()); + beneficiaryDetailsRmnch.setGenderId( + requestObj.get("genderID").getAsInt()); + beneficiaryDetailsRmnch.setReproductiveStatusId( + requestObj.get("maritalStatusID").getAsInt()); + + if (requestObj.get("maritalStatusName") != null + && !requestObj.get("maritalStatusName").isJsonNull()) { + beneficiaryDetailsRmnch.setReproductiveStatus( + requestObj.get("maritalStatusName").getAsString()); + } + + beneficiaryDetailsRmnch.setReproductiveStatusId( + requestObj.has("reproductiveStatusId") && !requestObj.get("reproductiveStatusId").isJsonNull() + ? requestObj.get("reproductiveStatusId").getAsInt() + : requestObj.get("maritalStatusID").getAsInt() + ); + + beneficiaryDetailsRmnch.setReproductiveStatus( + requestObj.has("reproductiveStatus") && !requestObj.get("reproductiveStatus").isJsonNull() + ? requestObj.get("reproductiveStatus").getAsString() + : null + ); + + rMNCHBeneficiaryDetailsRmnchRepo.save(beneficiaryDetailsRmnch); + logger.info("BeneficiaryDetailsRmnch saved for beneficiaryRegID: " + beneficiaryRegID); + + } catch (Exception e) { + logger.error("Error saving BeneficiaryDetailsRmnch: " + e.getMessage()); + throw e; + } + } + @Override public String getBenData(String requestOBJ, String authorisation) throws Exception { String outputResponse = null; From 58f3d5c2d10682a8a516a9d0a89a1c034da2fc43 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 18 Mar 2026 15:44:44 +0530 Subject: [PATCH 03/42] add status of women --- .../identity/controller/rmnch/RMNCHMobileAppController.java | 2 +- .../common/identity/service/rmnch/RmnchDataSyncService.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java index d9bec043..83153453 100644 --- a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java +++ b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java @@ -78,7 +78,7 @@ public String syncDataToAmritHwc(@RequestBody String requestOBJ) { OutputResponse response = new OutputResponse(); try { if (requestOBJ != null) { - String s = rmnchDataSyncService.syncDataToAmrit(requestOBJ); + String s = rmnchDataSyncService.saveBeneficiaryDetailsAfterRegistration(requestOBJ); response.setResponse(s); } else response.setError(5000, "Invalid/NULL request obj"); diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java index 1d343d4b..e7f18d14 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java @@ -23,6 +23,7 @@ public interface RmnchDataSyncService { public String syncDataToAmrit(String requestOBJ) throws Exception; + public String saveBeneficiaryDetailsAfterRegistration(String requestOBJ) throws Exception; public String getBenData(String requestOBJ, String authorisation) throws Exception; public String getBenDataByAsha(String requestOBJ, String authorisation) throws Exception; } From c16275af681623c9296c87b7d31b9d164d830bcd Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 18 Mar 2026 16:11:02 +0530 Subject: [PATCH 04/42] add status of women --- .../java/com/iemr/common/identity/dto/BeneficiariesDTO.java | 2 ++ .../com/iemr/common/identity/service/IdentityService.java | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/com/iemr/common/identity/dto/BeneficiariesDTO.java b/src/main/java/com/iemr/common/identity/dto/BeneficiariesDTO.java index d48cd9b5..0ecfb6b2 100644 --- a/src/main/java/com/iemr/common/identity/dto/BeneficiariesDTO.java +++ b/src/main/java/com/iemr/common/identity/dto/BeneficiariesDTO.java @@ -89,6 +89,8 @@ public int compareTo(BeneficiariesDTO ben) { private BigInteger religionId; private String religion; private String monthlyFamilyIncome; + private String reproductiveStatus; + private Integer reproductiveStatusId; // End Outreach // Start 1097 diff --git a/src/main/java/com/iemr/common/identity/service/IdentityService.java b/src/main/java/com/iemr/common/identity/service/IdentityService.java index 08b9fbbe..72d7d7e0 100644 --- a/src/main/java/com/iemr/common/identity/service/IdentityService.java +++ b/src/main/java/com/iemr/common/identity/service/IdentityService.java @@ -1996,6 +1996,11 @@ private BeneficiariesDTO getBeneficiariesDTO(MBeneficiarymapping benMap) { bdto.setFaceEmbedding(floatList); } // bdto.setOtherFields(benMap.getMBeneficiarydetail().getOtherFields()); + if(rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benMap.getBenRegId())!=null ){ + bdto.setReproductiveStatus(rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benMap.getBenRegId()).getMenstrualStatus()); + bdto.setReproductiveStatusId(rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benMap.getBenRegId()).getReproductiveStatusId()); + } + bdto.setBeneficiaryFamilyTags( mapper.mapToMBeneficiaryfamilymappingWithBenFamilyDTOList(benMap.getMBeneficiaryfamilymappings())); bdto.setBeneficiaryIdentites( From a137f00b88ab822bf5a63d5230cceab08f870ec6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 18 Mar 2026 16:11:31 +0530 Subject: [PATCH 05/42] add status of women --- .../java/com/iemr/common/identity/service/IdentityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/common/identity/service/IdentityService.java b/src/main/java/com/iemr/common/identity/service/IdentityService.java index 72d7d7e0..40f2d2e6 100644 --- a/src/main/java/com/iemr/common/identity/service/IdentityService.java +++ b/src/main/java/com/iemr/common/identity/service/IdentityService.java @@ -1997,7 +1997,7 @@ private BeneficiariesDTO getBeneficiariesDTO(MBeneficiarymapping benMap) { } // bdto.setOtherFields(benMap.getMBeneficiarydetail().getOtherFields()); if(rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benMap.getBenRegId())!=null ){ - bdto.setReproductiveStatus(rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benMap.getBenRegId()).getMenstrualStatus()); + bdto.setReproductiveStatus(rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benMap.getBenRegId()).getReproductiveStatus()); bdto.setReproductiveStatusId(rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benMap.getBenRegId()).getReproductiveStatusId()); } From e96a15247b2b8b10d0b679ad21a9bef87a758726 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 18 Mar 2026 16:15:24 +0530 Subject: [PATCH 06/42] add status of women --- .../common/identity/service/rmnch/RmnchDataSyncService.java | 5 ++++- .../identity/service/rmnch/RmnchDataSyncServiceImpl.java | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java index e7f18d14..845e79f9 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java @@ -23,7 +23,10 @@ public interface RmnchDataSyncService { public String syncDataToAmrit(String requestOBJ) throws Exception; - public String saveBeneficiaryDetailsAfterRegistration(String requestOBJ) throws Exception; + public String saveBeneficiaryDetailsAfterRegistration( + Long beneficiaryID, + Long beneficiaryRegID, + String comingRequest); public String getBenData(String requestOBJ, String authorisation) throws Exception; public String getBenDataByAsha(String requestOBJ, String authorisation) throws Exception; } diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 5b7bb79d..963b77ad 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -269,7 +269,7 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) - public void saveBeneficiaryDetailsAfterRegistration( + public String saveBeneficiaryDetailsAfterRegistration( Long beneficiaryID, Long beneficiaryRegID, String comingRequest) { @@ -323,6 +323,7 @@ public void saveBeneficiaryDetailsAfterRegistration( logger.error("Error saving BeneficiaryDetailsRmnch: " + e.getMessage()); throw e; } + return "BeneficiaryDetailsRmnch saved for beneficiaryRegID:"+beneficiaryID; } @Override From ef5827529dd08a79e3a01024d8386445f65b693e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 18 Mar 2026 16:25:54 +0530 Subject: [PATCH 07/42] add status of women --- .../rmnch/RMNCHMobileAppController.java | 47 ++++++++++++++----- .../rmnch/RmnchDataSyncServiceImpl.java | 4 ++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java index 83153453..6fa8df8f 100644 --- a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java +++ b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java @@ -23,10 +23,13 @@ import java.sql.Timestamp; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; @@ -73,21 +76,41 @@ public String syncDataToAmrit(@RequestBody String requestOBJ) { } @PostMapping(value = "/syncDataToAmritByHwc", consumes = "application/json", produces = "application/json") - @Operation(summary = "Sync data to AMRIT for already regestered beneficiary with AMRIT beneficiary id ") - public String syncDataToAmritHwc(@RequestBody String requestOBJ) { - OutputResponse response = new OutputResponse(); + @Operation(summary = "Sync data to AMRIT for already registered beneficiary with AMRIT beneficiary id") + public ResponseEntity syncDataToAmritHwc(@RequestBody String requestOBJ) { + try { - if (requestOBJ != null) { - String s = rmnchDataSyncService.saveBeneficiaryDetailsAfterRegistration(requestOBJ); - response.setResponse(s); - } else - response.setError(5000, "Invalid/NULL request obj"); + if (requestOBJ == null || requestOBJ.isEmpty()) { + return ResponseEntity.badRequest().body("Invalid/NULL request obj"); + } + + JsonObject requestObj = new Gson().fromJson(requestOBJ, JsonObject.class); + + Long beneficiaryID = requestObj.has("benficieryid") && !requestObj.get("benficieryid").isJsonNull() + ? requestObj.get("benficieryid").getAsLong() + : null; + + Long beneficiaryRegID = requestObj.has("benRegId") && !requestObj.get("benRegId").isJsonNull() + ? requestObj.get("benRegId").getAsLong() + : null; + + if (beneficiaryID == null || beneficiaryRegID == null) { + return ResponseEntity.badRequest().body("beneficiaryID or beneficiaryRegID is missing"); + } + + String result = rmnchDataSyncService.saveBeneficiaryDetailsAfterRegistration( + beneficiaryID, + beneficiaryRegID, + requestOBJ + ); + + return ResponseEntity.ok(result); + } catch (Exception e) { - logger.error("Error in RMNCH mobile data sync : {} " , e.getMessage()); - response.setError(5000, "Error in RMNCH mobile data sync : " + e); + logger.error("Error in RMNCH mobile data sync : {}", e.getMessage()); + return ResponseEntity.internalServerError() + .body("Error in RMNCH mobile data sync : " + e.getMessage()); } - return response.toString(); - } diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 963b77ad..3348267e 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -32,6 +32,8 @@ import java.util.Map; import java.util.regex.Pattern; +import com.iemr.common.identity.utils.OutputResponse; +import io.swagger.v3.oas.annotations.Operation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -77,6 +79,8 @@ import com.iemr.common.identity.utils.exception.IEMRException; import com.iemr.common.identity.utils.http.HttpUtils; import com.iemr.common.identity.utils.mapper.InputMapper; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; @Service @Qualifier("rmnchServiceImpl") From 452b8093fd08fcd15d3fc2b53ab2139d2e31e9c8 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 18 Mar 2026 18:12:05 +0530 Subject: [PATCH 08/42] add status of women --- .../iemr/common/identity/dto/IdentityDTO.java | 2 + .../rmnch/RmnchDataSyncServiceImpl.java | 86 +++++++++++-------- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/dto/IdentityDTO.java b/src/main/java/com/iemr/common/identity/dto/IdentityDTO.java index 322e57fc..f6c000cb 100644 --- a/src/main/java/com/iemr/common/identity/dto/IdentityDTO.java +++ b/src/main/java/com/iemr/common/identity/dto/IdentityDTO.java @@ -125,6 +125,8 @@ public class IdentityDTO { private Integer incomeStatusId; private String incomeStatus; private String monthlyFamilyIncome; + private String reproductiveStatus; + private Integer reproductiveStatusId; @Expose private Integer vanID; diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 3348267e..dc30d444 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -23,6 +23,7 @@ import java.math.BigInteger; import java.sql.Date; +import java.sql.Timestamp; import java.time.Period; import java.util.ArrayList; import java.util.Arrays; @@ -277,59 +278,74 @@ public String saveBeneficiaryDetailsAfterRegistration( Long beneficiaryID, Long beneficiaryRegID, String comingRequest) { + try { JsonObject requestObj = new Gson().fromJson(comingRequest, JsonObject.class); - RMNCHBeneficiaryDetailsRmnch beneficiaryDetailsRmnch = + RMNCHBeneficiaryDetailsRmnch entity = rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)); - if (beneficiaryDetailsRmnch == null) { - beneficiaryDetailsRmnch = new RMNCHBeneficiaryDetailsRmnch(); + if (entity == null) { + entity = new RMNCHBeneficiaryDetailsRmnch(); } - beneficiaryDetailsRmnch.setBenficieryid(BigInteger.valueOf(beneficiaryID)); - beneficiaryDetailsRmnch.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); - beneficiaryDetailsRmnch.setCreatedBy( - requestObj.get("createdBy").getAsString()); - beneficiaryDetailsRmnch.setVanID( - requestObj.get("vanID").getAsInt()); - beneficiaryDetailsRmnch.setParkingPlaceID( - requestObj.get("parkingPlaceID").getAsInt()); - beneficiaryDetailsRmnch.setProviderServiceMapID( - requestObj.get("providerServiceMapID").getAsInt()); - beneficiaryDetailsRmnch.setGenderId( - requestObj.get("genderID").getAsInt()); - beneficiaryDetailsRmnch.setReproductiveStatusId( - requestObj.get("maritalStatusID").getAsInt()); - - if (requestObj.get("maritalStatusName") != null - && !requestObj.get("maritalStatusName").isJsonNull()) { - beneficiaryDetailsRmnch.setReproductiveStatus( - requestObj.get("maritalStatusName").getAsString()); - } + String createdBy = getString(requestObj, "createdBy", "system"); + + entity.setBenficieryid(BigInteger.valueOf(beneficiaryID)); + entity.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); + entity.setCreatedBy(createdBy); + entity.setCreatedDate(new Timestamp(System.currentTimeMillis())); - beneficiaryDetailsRmnch.setReproductiveStatusId( - requestObj.has("reproductiveStatusId") && !requestObj.get("reproductiveStatusId").isJsonNull() - ? requestObj.get("reproductiveStatusId").getAsInt() - : requestObj.get("maritalStatusID").getAsInt() + entity.setVanID(getInt(requestObj, "vanID", null)); + entity.setParkingPlaceID(getInt(requestObj, "parkingPlaceID", null)); + entity.setProviderServiceMapID(getInt(requestObj, "providerServiceMapID", null)); + entity.setGenderId(getInt(requestObj, "genderID", null)); + + entity.setReproductiveStatusId( + getInt(requestObj, "reproductiveStatusId", + getInt(requestObj, "maritalStatusID", null)) ); - beneficiaryDetailsRmnch.setReproductiveStatus( - requestObj.has("reproductiveStatus") && !requestObj.get("reproductiveStatus").isJsonNull() - ? requestObj.get("reproductiveStatus").getAsString() - : null + entity.setReproductiveStatus( + getString(requestObj, "reproductiveStatus", null) ); - rMNCHBeneficiaryDetailsRmnchRepo.save(beneficiaryDetailsRmnch); - logger.info("BeneficiaryDetailsRmnch saved for beneficiaryRegID: " + beneficiaryRegID); + entity.setFirstName(getString(requestObj, "firstName", null)); + entity.setLastName(getString(requestObj, "lastName", null)); + entity.setFatherName(getString(requestObj, "fatherName", null)); + entity.setSpousename(getString(requestObj, "spouseName", null)); + entity.setMaritalstatusId(getInt(requestObj, "maritalStatusID", null)); + entity.setMaritalstatus(getString(requestObj, "maritalStatusName", null)); + + // DOB (String → Timestamp) + if (requestObj.has("dOB") && !requestObj.get("dOB").isJsonNull()) { + entity.setDob(Timestamp.valueOf( + requestObj.get("dOB").getAsString().replace("T", " ").replace("Z", "") + )); + } + + rMNCHBeneficiaryDetailsRmnchRepo.save(entity); + + logger.info("Saved RMNCH for benRegID: " + beneficiaryRegID); } catch (Exception e) { - logger.error("Error saving BeneficiaryDetailsRmnch: " + e.getMessage()); + logger.error("Error: ", e); throw e; } - return "BeneficiaryDetailsRmnch saved for beneficiaryRegID:"+beneficiaryID; + + return "Saved RMNCH for beneficiaryID: " + beneficiaryID; + } + private String getString(JsonObject obj, String key, String defaultVal) { + return (obj.has(key) && !obj.get(key).isJsonNull()) + ? obj.get(key).getAsString() + : defaultVal; } + private Integer getInt(JsonObject obj, String key, Integer defaultVal) { + return (obj.has(key) && !obj.get(key).isJsonNull()) + ? obj.get(key).getAsInt() + : defaultVal; + } @Override public String getBenData(String requestOBJ, String authorisation) throws Exception { String outputResponse = null; From 0f4f37830c6ffbfa0745d5f52c79f0f847c0b586 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 24 Mar 2026 12:45:26 +0530 Subject: [PATCH 09/42] add status of women --- .../identity/controller/IdentityController.java | 16 ++++++++++++++++ .../common/identity/service/IdentityService.java | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/src/main/java/com/iemr/common/identity/controller/IdentityController.java b/src/main/java/com/iemr/common/identity/controller/IdentityController.java index 16995734..74d9767b 100644 --- a/src/main/java/com/iemr/common/identity/controller/IdentityController.java +++ b/src/main/java/com/iemr/common/identity/controller/IdentityController.java @@ -30,10 +30,13 @@ import java.util.List; import java.util.Objects; +import com.iemr.common.identity.data.rmnch.RMNCHBeneficiaryDetailsRmnch; import org.apache.commons.lang3.StringUtils; 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.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -315,6 +318,19 @@ public String searchBeneficiaryByVillageIdAndLastModDate( } return response; } + + + @PostMapping("/getRmnchDataByBenRedID") + public ResponseEntity getRmnchDataByBenID( + @RequestBody BigInteger object) { + + try { + RMNCHBeneficiaryDetailsRmnch data = svc.getRmnchDataByBenID(object); + return ResponseEntity.ok(data); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + } // search beneficiary by lastModDate and districtID @Operation(summary ="Get count of beneficiary by villageId and last modified date-time") @PostMapping(path = "/countBenByVillageIdAndLastModifiedDate") diff --git a/src/main/java/com/iemr/common/identity/service/IdentityService.java b/src/main/java/com/iemr/common/identity/service/IdentityService.java index 40f2d2e6..c216b634 100644 --- a/src/main/java/com/iemr/common/identity/service/IdentityService.java +++ b/src/main/java/com/iemr/common/identity/service/IdentityService.java @@ -799,6 +799,12 @@ public List searchBeneficiaryByVillageIdAndLastModifyDate(List return beneficiaryList; } + + public RMNCHBeneficiaryDetailsRmnch getRmnchDataByBenID(BigInteger benID) { + + return rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benID); + } + public Long countBeneficiaryByVillageIdAndLastModifyDate(List villageIDs, Timestamp lastModifiedDate) { Long beneficiaryCount = 0L; try { From b46f36938e6f9cea550a8832083b0bee4e61bba6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 24 Mar 2026 14:22:40 +0530 Subject: [PATCH 10/42] add status of women --- .../rmnch/RmnchDataSyncServiceImpl.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index dc30d444..660547d9 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -115,7 +115,6 @@ public class RmnchDataSyncServiceImpl implements RmnchDataSyncService { private RMNCHBenContactRepo rMNCHBenContactRepo; @Autowired private RMNCHMBenRegIdMapRepo rMNCHMBenRegIdMapRepo; - @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) @Override public String syncDataToAmrit(String requestOBJ) throws Exception { @@ -273,6 +272,7 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { } + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public String saveBeneficiaryDetailsAfterRegistration( Long beneficiaryID, @@ -282,19 +282,30 @@ public String saveBeneficiaryDetailsAfterRegistration( try { JsonObject requestObj = new Gson().fromJson(comingRequest, JsonObject.class); + // ✅ use find instead of get RMNCHBeneficiaryDetailsRmnch entity = rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)); + boolean isNew = false; + if (entity == null) { entity = new RMNCHBeneficiaryDetailsRmnch(); + isNew = true; } String createdBy = getString(requestObj, "createdBy", "system"); entity.setBenficieryid(BigInteger.valueOf(beneficiaryID)); entity.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); - entity.setCreatedBy(createdBy); - entity.setCreatedDate(new Timestamp(System.currentTimeMillis())); + + // ✅ Only set created fields for new record + if (isNew) { + entity.setCreatedBy(createdBy); + entity.setCreatedDate(new Timestamp(System.currentTimeMillis())); + } else { + entity.setUpdatedBy(createdBy); + entity.setUpdatedDate(new Timestamp(System.currentTimeMillis())); + } entity.setVanID(getInt(requestObj, "vanID", null)); entity.setParkingPlaceID(getInt(requestObj, "parkingPlaceID", null)); @@ -317,7 +328,7 @@ public String saveBeneficiaryDetailsAfterRegistration( entity.setMaritalstatusId(getInt(requestObj, "maritalStatusID", null)); entity.setMaritalstatus(getString(requestObj, "maritalStatusName", null)); - // DOB (String → Timestamp) + // DOB if (requestObj.has("dOB") && !requestObj.get("dOB").isJsonNull()) { entity.setDob(Timestamp.valueOf( requestObj.get("dOB").getAsString().replace("T", " ").replace("Z", "") From 6e0d0f705c88dd63dfebeb16235700ba4c5ac28c Mon Sep 17 00:00:00 2001 From: Vanitha S <116701245+vanitha1822@users.noreply.github.com> Date: Fri, 22 May 2026 13:52:02 +0530 Subject: [PATCH 11/42] Merge Release 3.6.2 to Main (#163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Elasticsearch implementation for Beneficiary Search (#123) * fix: ES Implementation-mapping, indexing and async records * fix: add service for ES Search * fix: search implementation * fix: add additional fields as per the requirement * fix: comment extra fields * fix: rename the files, remove commented code * fix: update pom.xml * fix: revert advancesearch * fix: add properties * fix: coderabbit comments * fix: remove comment code * fix: accept numeric values for search * fix: update the env variable * fix: advance search functionality * fix: update the advance search ES functionality * fix: sync and fetch benid * fix: size limit issue * fix: improve response time * fix: updated the end point to advancedSearchES * fix: age issue while moving to nurse worklist (#130) * Optimize the Elasticsearch for better Response Time (#131) * fix: optimize the index and reduce the size * fix: align indent * fix: abha / health id issue * fix: sync optimization * fix: get abha created date * fix: state issue * fix: village issue * fix: add abha details * fix: abha fix and refresh index * fix: refresh index * fix: remove duplicate dependency * fix: fuzzy search, resume, refresh api's * fix: add middlename, maritalstatus * fix: remove refresh while bulk indexing * fix: add license * fix: remove the bean function to create the index automatically (#133) * Fix ES Issue in the Query (#137) * fix: ES Exception * fix: ES exception * Nd/vs/fix es (#138) * fix: ES Exception * fix: ES exception * fix: enable multi-word fuzzy search requirement (#139) * fix: enable multi-word fuzzy search requirement * Downgrade version from 3.6.2 to 3.6.1 * fix: multi-word search (#140) * Fix the column mismatch issue in beneficiary search (#142) * fix: column mismatch issue * fix: update marital status * add new column in rmnch table for death and child record * add new column in rmnch table for death and child record * Cherry-pick health and version API enhancements to release-3.6.1 (#145) * feat(health,version): add health and version endpoints * feat(health,version): add health and version endpoints without auth * fix(health): remove unused private methods * fix(health): fix exception issue * fix(health): redact error details for unauthenticated health checks * fix code quality issues and reduce cognitive complexity * feat(health): add MySQL health endpoint * refactor(health): simplify MySQL health check and remove sensitive details * fix(health): remove unused imports and variables * refactor(health): address nitpicks (configurable ES scheme, log noise, graceful shutdown, record) * fix(health): scope PROCESSLIST lock-wait check to application DB user * refactor(health): remove unused params and reuse response/error constants * fix(health): remove unused imports and methods * chore(health): clean up unused imports, params, and dead helpers * fix(health): avoid sharing JDBC connections across threads in advanced MySQL checks * refactor(health): reuse REDIS_COMPONENT constant and extract nested try block * fix(health): avoid blocking DB I/O under write lock and restore interrupt flag * fix(health): cancel in-flight futures on generic failure * feat(health,version): add index existance, read-only detection, canary write for elasticsearch health check * refactor(health): reduce cognitive complexity, remove dead throws, and clean code smells * Rebase 3.6.2 (#150) * fix: enable multi-word fuzzy search requirement (#139) * fix: enable multi-word fuzzy search requirement * Downgrade version from 3.6.2 to 3.6.1 * fix: multi-word search (#140) * Fix the column mismatch issue in beneficiary search (#142) * fix: column mismatch issue * fix: update marital status * add new column in rmnch table for death and child record * add new column in rmnch table for death and child record * Cherry-pick health and version API enhancements to release-3.6.1 (#145) * feat(health,version): add health and version endpoints * feat(health,version): add health and version endpoints without auth * fix(health): remove unused private methods * fix(health): fix exception issue * fix(health): redact error details for unauthenticated health checks * fix code quality issues and reduce cognitive complexity * feat(health): add MySQL health endpoint * refactor(health): simplify MySQL health check and remove sensitive details * fix(health): remove unused imports and variables * refactor(health): address nitpicks (configurable ES scheme, log noise, graceful shutdown, record) * fix(health): scope PROCESSLIST lock-wait check to application DB user * refactor(health): remove unused params and reuse response/error constants * fix(health): remove unused imports and methods * chore(health): clean up unused imports, params, and dead helpers * fix(health): avoid sharing JDBC connections across threads in advanced MySQL checks * refactor(health): reuse REDIS_COMPONENT constant and extract nested try block * fix(health): avoid blocking DB I/O under write lock and restore interrupt flag * fix(health): cancel in-flight futures on generic failure * feat(health,version): add index existance, read-only detection, canary write for elasticsearch health check * refactor(health): reduce cognitive complexity, remove dead throws, and clean code smells --------- Co-authored-by: Saurav Mishra Co-authored-by: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Co-authored-by: KOPPIREDDY DURGA PRASAD <144464542+DurgaPrasad-54@users.noreply.github.com> * feat(jwt): enhance jwt validation logging and public endpoint check (#151) * fix: pom version (#152) * Add the missing properties for 1097_Preprod (#153) * fix: add the missing properties * fix: update db url * docs: add CLAUDE.md for Claude Code guidance * fix: map sexualOrientationID during beneficiary update in 1097 convertIdentityEditDTOToMBeneficiarydetail() was missing sexualOrientationID and sexualOrientationType, so the field was never persisted on update. Co-Authored-By: Claude Sonnet 4.6 * Sexual orientation data not reflecting under DB record (#157) * fix: enable multi-word fuzzy search requirement (#139) * fix: enable multi-word fuzzy search requirement * Downgrade version from 3.6.2 to 3.6.1 * fix: multi-word search (#140) * Fix the column mismatch issue in beneficiary search (#142) * fix: column mismatch issue * fix: update marital status * add new column in rmnch table for death and child record * add new column in rmnch table for death and child record * Cherry-pick health and version API enhancements to release-3.6.1 (#145) * feat(health,version): add health and version endpoints * feat(health,version): add health and version endpoints without auth * fix(health): remove unused private methods * fix(health): fix exception issue * fix(health): redact error details for unauthenticated health checks * fix code quality issues and reduce cognitive complexity * feat(health): add MySQL health endpoint * refactor(health): simplify MySQL health check and remove sensitive details * fix(health): remove unused imports and variables * refactor(health): address nitpicks (configurable ES scheme, log noise, graceful shutdown, record) * fix(health): scope PROCESSLIST lock-wait check to application DB user * refactor(health): remove unused params and reuse response/error constants * fix(health): remove unused imports and methods * chore(health): clean up unused imports, params, and dead helpers * fix(health): avoid sharing JDBC connections across threads in advanced MySQL checks * refactor(health): reuse REDIS_COMPONENT constant and extract nested try block * fix(health): avoid blocking DB I/O under write lock and restore interrupt flag * fix(health): cancel in-flight futures on generic failure * feat(health,version): add index existance, read-only detection, canary write for elasticsearch health check * refactor(health): reduce cognitive complexity, remove dead throws, and clean code smells * fix: map sexualOrientationID during beneficiary update in 1097 convertIdentityEditDTOToMBeneficiarydetail() was missing sexualOrientationID and sexualOrientationType, so the field was never persisted on update. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Vanitha S <116701245+vanitha1822@users.noreply.github.com> Co-authored-by: Saurav Mishra Co-authored-by: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Co-authored-by: KOPPIREDDY DURGA PRASAD <144464542+DurgaPrasad-54@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 * feat: add getBenFamilyDetails API and fix searchFamily queries - Add POST /family/getBenFamilyDetails endpoint that returns full family details (master record + all members) for a given beneficiaryRegId - Fix searchFamily and searchFamilyWithFamilyId queries: replace noOfmembers > 0 guard with deleted=false filter so families with zero/null member count and soft-deleted records are handled correctly; also make villageId optional and use LIKE prefix match for familyName Co-Authored-By: Claude Sonnet 4.6 * fix: preserve existing occupation and education when incoming values are null During beneficiary edit, convertIdentityEditDTOToMBeneficiarydetail creates a fresh entity and overwrites all columns on save. Added null-guards for occupationId, occupation, educationId, and education so existing DB values are preserved when the incoming DTO omits them — consistent with the existing pattern for familyId and headOfFamily_Relation. Co-Authored-By: Claude Sonnet 4.6 * fix: replace in-memory queue with SELECT FOR UPDATE SKIP LOCKED for BenRegId allocation (#159) * aam-2126 Memeberlist is not displying properly * fix: aam-2313 phone number leading with zero - removed zero (#161) * Allowing numbers with zero is search by phone number. (#162) * fix: aam-2313 phone number leading with zero - removed zero * fix: aam-2313 serach by user phone number fix for number leading with zero --------- Co-authored-by: Saurav Mishra Co-authored-by: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Co-authored-by: KOPPIREDDY DURGA PRASAD <144464542+DurgaPrasad-54@users.noreply.github.com> Co-authored-by: SnehaRH Co-authored-by: Claude Sonnet 4.6 Co-authored-by: SnehaRH <77656297+snehar-nd@users.noreply.github.com> --- CLAUDE.md | 73 +++++++++++++++ pom.xml | 2 +- src/main/environment/1097_ci.properties | 1 - src/main/environment/1097_example.properties | 1 - .../FamilyTaggingController.java | 14 +++ .../common/identity/repo/BenContactRepo.java | 10 ++- .../identity/repo/BenRegIdMappingRepo.java | 9 ++ .../repo/familyTag/FamilyTagRepo.java | 8 +- .../service/BenRegIdClaimService.java | 89 +++++++++++++++++++ .../identity/service/IdentityService.java | 60 +++++++------ .../familyTagging/FamilyTagService.java | 2 + .../familyTagging/FamilyTagServiceImpl.java | 44 ++++++++- .../utils/JwtUserIdValidationFilter.java | 7 +- 13 files changed, 279 insertions(+), 41 deletions(-) create mode 100644 CLAUDE.md create mode 100644 src/main/java/com/iemr/common/identity/service/BenRegIdClaimService.java diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..ae3f45c7 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,73 @@ +# CLAUDE.md - Identity-API + +## Project Overview + +Identity-API is the beneficiary identity management service for the AMRIT platform. It handles beneficiary creation, search, update, and deduplication across dual database profiles (`db_iemr` main and `db_identity`). It supports RMNCH (Reproductive, Maternal, Newborn, Child, and Adolescent Health) data management, family tagging, Elasticsearch-based beneficiary search, and health ID linkage. + +## Tech Stack + +- Java 17, Spring Boot 3.2.2, Maven +- Spring Data JPA / Hibernate, MySQL 8.0 +- Elasticsearch (Spring Data Elasticsearch for beneficiary search indexing) +- Redis for session management +- Lombok (1.18.36), MapStruct +- SpringDoc OpenAPI (Swagger UI at `/swagger-ui.html`) +- ECS logging (logback-ecs-encoder) +- JaCoCo for test coverage +- Packaged as WAR for Wildfly deployment + +## Build & Run + +```bash +mvn clean install -DENV_VAR=local # Build +mvn spring-boot:run -DENV_VAR=local # Run locally +mvn -B package --file pom.xml -P # Package WAR (dev, local, test, ci, uat) +mvn test # Run tests +``` + +Environment config: `src/main/resources/common_.properties` is copied to `application.properties` at build time. + +## Key Packages (`com.iemr.common.identity`) + +- **controller/** - REST endpoints: + - `IdentityController` - Core beneficiary CRUD (create, search, update, search by phone/ID/name) + - `IdentityESController` - Elasticsearch-based beneficiary search + - `rmnch/RMNCHMobileAppController` - RMNCH mobile app data sync + - `familyTagging/FamilyTaggingController` - Family tagging and family search + - `elasticsearch/ElasticsearchSyncController` - Elasticsearch sync management + - `health/HealthController` - Health check endpoint + - `version/VersionController` - API version info +- **service/** - Business logic: + - `IdentityService` - Core identity operations + - `rmnch/` - RMNCH beneficiary management + - `familyTagging/` - Family tagging logic + - `elasticsearch/` - Elasticsearch indexing and sync + - `health/` - Health check service +- **domain/** - Core JPA entities for beneficiary data: + - `MBeneficiaryregidmapping` - Beneficiary registration ID mapping + - `MBeneficiaryaddress`, `MBeneficiarycontact`, `MBeneficiaryAccount` - Beneficiary demographics + - `MBeneficiaryfamilymapping` - Family relationships + - `MBeneficiaryconsent` - Consent management + - `VBenAdvanceSearch` - View for advanced search queries +- **data/** - Additional data models: + - `rmnch/` - RMNCH-specific entities (CBAC details, born birth details, household details, NCD/TB/HRP data) + - `elasticsearch/` - Elasticsearch document models and sync job + - `familyTagging/` - Family tagging models +- **dto/** - Data transfer objects for API requests/responses +- **repo/** - Spring Data JPA and Elasticsearch repositories +- **mapper/** - MapStruct mappers for entity-DTO conversion +- **filter/** - Servlet filters +- **security/** - Security configuration +- **utils/** - Utilities (Redis, HTTP, validation, session, gateway, email, exception handling) +- **config/** - Application configuration + +## Architecture Notes + +- Dual-profile beneficiary storage: main identity in `db_identity`, with mapping to `db_iemr` for AMRIT platform integration +- Elasticsearch integration provides fast full-text beneficiary search with background sync jobs +- RMNCH module handles field-worker mobile app data (CBAC screening, household surveys, birth details) +- Family tagging enables linking beneficiaries into family units with search by family ID +- MapStruct mappers handle complex entity-to-DTO transformations +- Health ID (ABHA) linkage stored per beneficiary for ABDM integration +- Beneficiary deduplication logic via advanced search views +- Artifact ID: `identity-api`, group: `com.iemr.common.identity`, version: 3.6.1 diff --git a/pom.xml b/pom.xml index f29361fd..c3b57f1c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.iemr.common.identity identity-api - 3.6.1 + 3.6.2 war diff --git a/src/main/environment/1097_ci.properties b/src/main/environment/1097_ci.properties index 0e8deded..514f675d 100644 --- a/src/main/environment/1097_ci.properties +++ b/src/main/environment/1097_ci.properties @@ -24,7 +24,6 @@ spring.redis.host=@env.REDIS_HOST@ cors.allowed-origins=@env.CORS_ALLOWED_ORIGINS@ - # Elasticsearch Configuration elasticsearch.host=@env.ELASTICSEARCH_HOST@ elasticsearch.port=@env.ELASTICSEARCH_PORT@ diff --git a/src/main/environment/1097_example.properties b/src/main/environment/1097_example.properties index ab87d360..ba2f3211 100644 --- a/src/main/environment/1097_example.properties +++ b/src/main/environment/1097_example.properties @@ -31,4 +31,3 @@ elasticsearch.index.beneficiary=beneficiary_index # Enable/Disable ES (for gradual rollout) elasticsearch.enabled=true - diff --git a/src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java b/src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java index 19323611..b347bd50 100644 --- a/src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java +++ b/src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java @@ -116,6 +116,20 @@ public String untagFamily(@RequestBody String comingReq) { return response.toString(); } + @Operation(summary = "Get family tagging details by beneficiary ID") + @PostMapping(value = { "/getBenFamilyDetails" }, consumes = "application/json", produces = "application/json") + public String getFamilyDetailsByBeneficiaryId(@RequestBody String comingReq) { + OutputResponse response = new OutputResponse(); + try { + String s = familyTagService.getFamilyDetailsByBeneficiaryId(comingReq); + response.setResponse(s); + } catch (Exception e) { + logger.error("Error in fetching family details by beneficiary ID : " + e); + response.setError(5000, "Error in fetching family details by beneficiary ID : " + e.getLocalizedMessage()); + } + return response.toString(); + } + @Operation(summary = "Edit beneficiary family details") @PostMapping(value = { "/editFamilyTagging" }, consumes = "application/json", produces = "application/json") public String editFamilyDetails(@RequestBody String comingReq) { diff --git a/src/main/java/com/iemr/common/identity/repo/BenContactRepo.java b/src/main/java/com/iemr/common/identity/repo/BenContactRepo.java index fdbda216..02334684 100644 --- a/src/main/java/com/iemr/common/identity/repo/BenContactRepo.java +++ b/src/main/java/com/iemr/common/identity/repo/BenContactRepo.java @@ -49,8 +49,12 @@ public interface BenContactRepo extends CrudRepository findByPreferredSMSPhoneNumOrderByBenContactsIDAsc(String smsPhoneNum); - @Query("select c from MBeneficiarycontact c where c.preferredPhoneNum = :phoneNum ") - List findByAnyPhoneNum(@Param("phoneNum") String phoneNum); + // @Query("select c from MBeneficiarycontact c where c.preferredPhoneNum = :phoneNum ") + // List findByAnyPhoneNum(@Param("phoneNum") String phoneNum); + + @Query("select c from MBeneficiarycontact c where c.preferredPhoneNum IN :variants") + List findByAnyPhoneNum(@Param("variants") List variants); + @Query("select c from MBeneficiarycontact c where c.preferredPhoneNum = :phoneNum or c.phoneNum1 = :phoneNum " @@ -70,4 +74,6 @@ public interface BenContactRepo extends CrudRepository findTop10000ByProvisionedAndReserved(Boolean isProvisioned,Boolean isReserved); + /** + * Atomically selects and locks the next available registration ID row. + * SKIP LOCKED ensures concurrent servers each get a distinct row without blocking each other, + * eliminating duplicate BenRegId assignments when multiple app instances share the same database. + */ + @Transactional + @Query(value = "SELECT * FROM m_beneficiaryregidmapping WHERE Provisioned = false AND Reserved = false ORDER BY BenRegId ASC LIMIT 1 FOR UPDATE SKIP LOCKED", nativeQuery = true) + MBeneficiaryregidmapping findAndLockNextAvailable(); + } diff --git a/src/main/java/com/iemr/common/identity/repo/familyTag/FamilyTagRepo.java b/src/main/java/com/iemr/common/identity/repo/familyTag/FamilyTagRepo.java index 4451fd37..88d05388 100644 --- a/src/main/java/com/iemr/common/identity/repo/familyTag/FamilyTagRepo.java +++ b/src/main/java/com/iemr/common/identity/repo/familyTag/FamilyTagRepo.java @@ -42,12 +42,10 @@ public interface FamilyTagRepo extends CrudRepository { public int untagFamily(@Param("benFamilyTagId") List benFamilyTagId,@Param("modifiedBy") String modifiedBy); - @Query("SELECT obj FROM BenFamilyMapping obj WHERE obj.familyName =:familyName AND obj.villageId =:villageId AND (obj.noOfmembers is not null " - + " AND obj.noOfmembers >0)") + @Query("SELECT obj FROM BenFamilyMapping obj WHERE obj.familyName LIKE CONCAT(:familyName, '%') AND (:villageId IS NULL OR obj.villageId =:villageId) AND (obj.deleted IS NULL OR obj.deleted = false)") List searchFamily(@Param("familyName") String familyName,@Param("villageId") Integer villageId); - - @Query("SELECT obj FROM BenFamilyMapping obj WHERE obj.familyName =:familyName AND obj.villageId =:villageId AND obj.familyId =:familyId AND (obj.noOfmembers is not null " - + " AND obj.noOfmembers >0)") + + @Query("SELECT obj FROM BenFamilyMapping obj WHERE obj.familyName LIKE CONCAT(:familyName, '%') AND (:villageId IS NULL OR obj.villageId =:villageId) AND obj.familyId =:familyId AND (obj.deleted IS NULL OR obj.deleted = false)") List searchFamilyWithFamilyId(@Param("familyName") String familyName,@Param("villageId") Integer villageId,@Param("familyId") String familyId); @Query("SELECT obj FROM BenFamilyMapping obj WHERE obj.familyId =:familyId") diff --git a/src/main/java/com/iemr/common/identity/service/BenRegIdClaimService.java b/src/main/java/com/iemr/common/identity/service/BenRegIdClaimService.java new file mode 100644 index 00000000..ba2c32eb --- /dev/null +++ b/src/main/java/com/iemr/common/identity/service/BenRegIdClaimService.java @@ -0,0 +1,89 @@ +/* +* 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.common.identity.service; + +import java.sql.Timestamp; + +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.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import com.iemr.common.identity.domain.MBeneficiaryregidmapping; +import com.iemr.common.identity.repo.BenRegIdMappingRepo; + +/** + * Handles atomic beneficiary registration ID claiming. + * + * Uses SELECT ... FOR UPDATE SKIP LOCKED so that each application instance + * obtains a distinct, exclusive row. Multiple servers sharing the same database + * will never receive the same BenRegId, preventing + * SQLIntegrityConstraintViolationException duplicate-key errors that occurred + * with the previous in-memory ArrayDeque queue approach. + * + * REQUIRES_NEW propagation ensures the SELECT + UPDATE happens in its own + * short-lived transaction, releasing the row lock immediately after the ID is + * marked reserved — keeping lock contention to a minimum. + */ +@Service +public class BenRegIdClaimService { + + private static final Logger logger = LoggerFactory.getLogger(BenRegIdClaimService.class); + + @Autowired + private BenRegIdMappingRepo regIdRepo; + + /** + * Atomically claims the next available registration ID. + * + *
    + *
  1. Opens a brand-new transaction (REQUIRES_NEW).
  2. + *
  3. Executes SELECT … FOR UPDATE SKIP LOCKED to lock exactly one row. + * Concurrent callers on other servers/threads skip the locked row and + * get the next one — no two callers ever see the same row.
  4. + *
  5. Marks the row {@code reserved = true} and flushes it within the same + * transaction so the change is visible to other connections the moment + * this method returns.
  6. + *
+ * + * @return the reserved {@link MBeneficiaryregidmapping} with {@code reserved=true} + * @throws IllegalStateException if the ID pool is exhausted + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public MBeneficiaryregidmapping claimNextAvailableRegId() { + MBeneficiaryregidmapping regMap = regIdRepo.findAndLockNextAvailable(); + if (regMap == null) { + throw new IllegalStateException( + "No available registration IDs in the pool. " + + "Please contact the system administrator to import more IDs."); + } + if (regMap.getCreatedDate() == null) { + regMap.setCreatedDate(new Timestamp(System.currentTimeMillis())); + } + regMap.setReserved(true); + regMap = regIdRepo.save(regMap); + logger.info("BenRegIdClaimService: claimed BenRegId={}", regMap.getBenRegId()); + return regMap; + } +} diff --git a/src/main/java/com/iemr/common/identity/service/IdentityService.java b/src/main/java/com/iemr/common/identity/service/IdentityService.java index 08b9fbbe..afb193e3 100644 --- a/src/main/java/com/iemr/common/identity/service/IdentityService.java +++ b/src/main/java/com/iemr/common/identity/service/IdentityService.java @@ -25,8 +25,8 @@ import java.math.BigInteger; import java.sql.Timestamp; import java.text.SimpleDateFormat; -import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -154,6 +154,8 @@ private JdbcTemplate getJdbcTemplate() { @Autowired BenRegIdMappingRepo regIdRepo; @Autowired + private BenRegIdClaimService benRegIdClaimService; + @Autowired BenServiceMappingRepo serviceMapRepo; @Autowired MBeneficiaryAccountRepo accountRepo; @@ -555,7 +557,15 @@ public List getBeneficiariesByPhoneNum(String phoneNum) List list = new ArrayList<>(); try { - List benContact = contactRepo.findByAnyPhoneNum(phoneNum); + // List benContact = contactRepo.findByAnyPhoneNum(phoneNum); + + String clean = phoneNum.trim(); + if (clean.startsWith("+91")) clean = clean.substring(3); + else if (clean.startsWith("91") && clean.length() == 12) clean = clean.substring(2); + else if (clean.startsWith("0") && clean.length() == 11) clean = clean.substring(1); + + List variants = Arrays.asList(clean, "0" + clean, "91" + clean, "+91" + clean); + List benContact = contactRepo.findByAnyPhoneNum(variants); logger.info(benContact.size() + " contacts found for phone number " + phoneNum); @@ -1038,6 +1048,18 @@ public void editIdentity(IdentityEditDTO identity) throws MissingMandatoryFields if (benDetails.getOther() != null) { mbDetl.setOther(benDetails.getOther()); } + if (mbDetl.getOccupationId() == null && benDetails.getOccupationId() != null) { + mbDetl.setOccupationId(benDetails.getOccupationId()); + } + if (mbDetl.getOccupation() == null && benDetails.getOccupation() != null) { + mbDetl.setOccupation(benDetails.getOccupation()); + } + if (mbDetl.getEducationId() == null && benDetails.getEducationId() != null) { + mbDetl.setEducationId(benDetails.getEducationId()); + } + if (mbDetl.getEducation() == null && benDetails.getEducation() != null) { + mbDetl.setEducation(benDetails.getEducation()); + } // Extract and set extra fields // String identityJson = new Gson().toJson(json); @@ -1337,6 +1359,8 @@ private MBeneficiarydetail convertIdentityEditDTOToMBeneficiarydetail(IdentityEd if (dto.getOtherFields() != null) { beneficiarydetail.setOtherFields(dto.getOtherFields()); } + beneficiarydetail.setSexualOrientationID(dto.getSexualOrientationID()); + beneficiarydetail.setSexualOrientationType(dto.getSexualOrientationType()); return beneficiarydetail; } @@ -1345,34 +1369,13 @@ private MBeneficiarydetail convertIdentityEditDTOToMBeneficiarydetail(IdentityEd * @param identity * @return */ - ArrayDeque queue = new ArrayDeque<>(); - public BeneficiaryCreateResp createIdentity(IdentityDTO identity) { logger.info("IdentityService.createIdentity - start"); - List list = null; - MBeneficiaryregidmapping regMap = null; - synchronized (queue) { - if (queue.isEmpty()) { - logger.info("fetching 10000 rows"); - list = regIdRepo.findTop10000ByProvisionedAndReserved(false, false); - logger.info("Adding SynchronousQueue start-- "); - for (MBeneficiaryregidmapping map : list) { - queue.add(map); - } - logger.info("Adding SynchronousQueue end-- "); - } - regMap = queue.removeFirst(); - } - regMap.setReserved(true); - if (regMap.getCreatedDate() == null) { - SimpleDateFormat sdf = new SimpleDateFormat(CREATED_DATE_FORMAT); - String dateToStoreInDataBase = sdf.format(new Date()); - Timestamp ts = Timestamp.valueOf(dateToStoreInDataBase); - regMap.setCreatedDate(ts); - } - - regIdRepo.save(regMap); + // Atomically claim the next available ID using SELECT … FOR UPDATE SKIP LOCKED. + // This is safe across multiple app servers sharing the same database — each server + // locks and reserves a distinct row, so duplicate BenRegId inserts cannot occur. + MBeneficiaryregidmapping regMap = benRegIdClaimService.claimNextAvailableRegId(); regMap.setProvisioned(true); @@ -1665,6 +1668,9 @@ private String cleanPhoneNumber(String phoneNumber) { } else if (cleaned.startsWith("91") && cleaned.length() == 12) { // Handle case where + is already removed but 91 remains cleaned = cleaned.substring(2); + } else if (cleaned.startsWith("0") && cleaned.length() == 11) { + // Handle case where number starts with 0 and is 11 digits long + cleaned = cleaned.substring(1); } return cleaned.trim(); diff --git a/src/main/java/com/iemr/common/identity/service/familyTagging/FamilyTagService.java b/src/main/java/com/iemr/common/identity/service/familyTagging/FamilyTagService.java index 85e8cfba..5bf22b36 100644 --- a/src/main/java/com/iemr/common/identity/service/familyTagging/FamilyTagService.java +++ b/src/main/java/com/iemr/common/identity/service/familyTagging/FamilyTagService.java @@ -36,4 +36,6 @@ public interface FamilyTagService { public String searchFamily(String request) throws IEMRException; public String editFamilyDetails(String request) throws IEMRException; + + public String getFamilyDetailsByBeneficiaryId(String request) throws IEMRException; } diff --git a/src/main/java/com/iemr/common/identity/service/familyTagging/FamilyTagServiceImpl.java b/src/main/java/com/iemr/common/identity/service/familyTagging/FamilyTagServiceImpl.java index 2a60571b..f44eecf8 100644 --- a/src/main/java/com/iemr/common/identity/service/familyTagging/FamilyTagServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/familyTagging/FamilyTagServiceImpl.java @@ -37,6 +37,7 @@ import com.google.gson.JsonParser; import com.iemr.common.identity.data.familyTagging.BenFamilyMapping; import com.iemr.common.identity.data.familyTagging.FamilyMembers; +import com.iemr.common.identity.data.familyTagging.FamilySearchResponse; import com.iemr.common.identity.domain.MBeneficiarydetail; import com.iemr.common.identity.domain.MBeneficiarymapping; import com.iemr.common.identity.exception.IEMRException; @@ -264,10 +265,49 @@ public String getFamilyDetails(String request) throws IEMRException { throw new IEMRException("Error while fetching family member details :" + e.getLocalizedMessage()); } } + @Override + public String getFamilyDetailsByBeneficiaryId(String request) throws IEMRException { + try { + BenFamilyMapping reqObj = InputMapper.gson().fromJson(request, BenFamilyMapping.class); + if (reqObj.getBeneficiaryRegId() == null) + throw new IEMRException("beneficiaryRegId is required"); + + MBeneficiarymapping mapping = benMappingRepo + .getBenDetailsId(BigInteger.valueOf(reqObj.getBeneficiaryRegId())); + if (mapping == null || mapping.getBenDetailsId() == null) + throw new IEMRException("Beneficiary not found"); + + List benDetails = benDetailRepo + .findByBeneficiaryDetailsIdOrderByBeneficiaryDetailsIdAsc(mapping.getBenDetailsId()); + if (benDetails == null || benDetails.isEmpty() || benDetails.get(0).getFamilyId() == null) + return "No family tagged to this beneficiary"; + + String familyId = benDetails.get(0).getFamilyId(); + + BenFamilyMapping familyMaster = familyTagRepo.searchFamilyByFamilyId(familyId); + List memberList = benDetailRepo.getFamilyDetails(familyId); + + FamilySearchResponse resp = new FamilySearchResponse(); + if (familyMaster != null) { + resp.setFamilyId(familyMaster.getFamilyId()); + resp.setFamilyName(familyMaster.getFamilyName()); + resp.setHeadOfTheFamily(familyMaster.getFamilyHeadName()); + resp.setNoOfMembers(familyMaster.getNoOfmembers()); + } + List memberResponseList = new ArrayList<>(); + addFamilyMembersToList(memberList, memberResponseList); + resp.setFamilyMembers(memberResponseList); + + return new Gson().toJson(resp); + } catch (Exception e) { + throw new IEMRException( + "Error while fetching family details by beneficiary ID : " + e.getLocalizedMessage()); + } + } + private void addFamilyMembersToList(List list, List responseList) { - StringBuilder name = new StringBuilder(""); for (MBeneficiarydetail obj : list) { - + StringBuilder name = new StringBuilder(""); FamilyMembers famObj = new FamilyMembers(); BigInteger benRegId = benMappingRepo.getBenRegId(obj.getBeneficiaryDetailsId(), obj.getVanID()); if (benRegId != null) diff --git a/src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java index af81ea34..cf959aa6 100644 --- a/src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java @@ -43,10 +43,13 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo return; } String path = request.getRequestURI(); - logger.info("JwtUserIdValidationFilter invoked for path: {}", path); + + String servletPath = request.getServletPath(); + logger.info("JwtUserIdValidationFilter invoked for requestURI: {}, servletPath: {}", path, servletPath); // Skip JWT validation for public endpoints - if (path.equals("/health") || path.equals("/version")) { + if (servletPath.equals("/health") || servletPath.equals("/version") || + path.endsWith("/health") || path.endsWith("/version")) { logger.info("Public endpoint accessed: {} - skipping JWT validation", path); filterChain.doFilter(servletRequest, servletResponse); return; From 9fa18573308f58b1f2b282c1842d074ce7b81699 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 4 Jun 2026 18:40:39 +0530 Subject: [PATCH 12/42] merge with release-3.6.2 --- .../rmnch/RmnchDataSyncServiceImpl.java | 95 ++++++++++--------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 600ccd5b..07904279 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -287,59 +287,64 @@ public String saveBeneficiaryDetailsAfterRegistration( JsonObject requestObj = new Gson().fromJson(comingRequest, JsonObject.class); // ✅ use find instead of get - RMNCHBeneficiaryDetailsRmnch entity = - rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)); + if(!rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)).isEmpty()){ + RMNCHBeneficiaryDetailsRmnch entity = + rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)).get(0); - boolean isNew = false; + boolean isNew = false; - if (entity == null) { - entity = new RMNCHBeneficiaryDetailsRmnch(); - isNew = true; - } + if (entity == null) { + entity = new RMNCHBeneficiaryDetailsRmnch(); + isNew = true; + } - String createdBy = getString(requestObj, "createdBy", "system"); + String createdBy = getString(requestObj, "createdBy", "system"); - entity.setBenficieryid(BigInteger.valueOf(beneficiaryID)); - entity.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); + entity.setBenficieryid(BigInteger.valueOf(beneficiaryID)); + entity.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); - // ✅ Only set created fields for new record - if (isNew) { - entity.setCreatedBy(createdBy); - entity.setCreatedDate(new Timestamp(System.currentTimeMillis())); - } else { - entity.setUpdatedBy(createdBy); - entity.setUpdatedDate(new Timestamp(System.currentTimeMillis())); - } + // ✅ Only set created fields for new record + if (isNew) { + entity.setCreatedBy(createdBy); + entity.setCreatedDate(new Timestamp(System.currentTimeMillis())); + } else { + entity.setUpdatedBy(createdBy); + entity.setUpdatedDate(new Timestamp(System.currentTimeMillis())); + } + + entity.setVanID(getInt(requestObj, "vanID", null)); + entity.setParkingPlaceID(getInt(requestObj, "parkingPlaceID", null)); + entity.setProviderServiceMapID(getInt(requestObj, "providerServiceMapID", null)); + entity.setGenderId(getInt(requestObj, "genderID", null)); + + entity.setReproductiveStatusId( + getInt(requestObj, "reproductiveStatusId", + getInt(requestObj, "maritalStatusID", null)) + ); + + entity.setReproductiveStatus( + getString(requestObj, "reproductiveStatus", null) + ); + + entity.setFirstName(getString(requestObj, "firstName", null)); + entity.setLastName(getString(requestObj, "lastName", null)); + entity.setFatherName(getString(requestObj, "fatherName", null)); + entity.setSpousename(getString(requestObj, "spouseName", null)); + entity.setMaritalstatusId(getInt(requestObj, "maritalStatusID", null)); + entity.setMaritalstatus(getString(requestObj, "maritalStatusName", null)); + + // DOB + if (requestObj.has("dOB") && !requestObj.get("dOB").isJsonNull()) { + entity.setDob(Timestamp.valueOf( + requestObj.get("dOB").getAsString().replace("T", " ").replace("Z", "") + )); + } + + rMNCHBeneficiaryDetailsRmnchRepo.save(entity); - entity.setVanID(getInt(requestObj, "vanID", null)); - entity.setParkingPlaceID(getInt(requestObj, "parkingPlaceID", null)); - entity.setProviderServiceMapID(getInt(requestObj, "providerServiceMapID", null)); - entity.setGenderId(getInt(requestObj, "genderID", null)); - - entity.setReproductiveStatusId( - getInt(requestObj, "reproductiveStatusId", - getInt(requestObj, "maritalStatusID", null)) - ); - - entity.setReproductiveStatus( - getString(requestObj, "reproductiveStatus", null) - ); - - entity.setFirstName(getString(requestObj, "firstName", null)); - entity.setLastName(getString(requestObj, "lastName", null)); - entity.setFatherName(getString(requestObj, "fatherName", null)); - entity.setSpousename(getString(requestObj, "spouseName", null)); - entity.setMaritalstatusId(getInt(requestObj, "maritalStatusID", null)); - entity.setMaritalstatus(getString(requestObj, "maritalStatusName", null)); - - // DOB - if (requestObj.has("dOB") && !requestObj.get("dOB").isJsonNull()) { - entity.setDob(Timestamp.valueOf( - requestObj.get("dOB").getAsString().replace("T", " ").replace("Z", "") - )); } - rMNCHBeneficiaryDetailsRmnchRepo.save(entity); + logger.info("Saved RMNCH for benRegID: " + beneficiaryRegID); From b95b68ecd37b875ce9b5b6dd7538d336ecf75bd1 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 4 Jun 2026 20:39:55 +0530 Subject: [PATCH 13/42] merge with release-3.6.2 --- .../com/iemr/common/identity/service/IdentityService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/common/identity/service/IdentityService.java b/src/main/java/com/iemr/common/identity/service/IdentityService.java index a84febff..d0baad39 100644 --- a/src/main/java/com/iemr/common/identity/service/IdentityService.java +++ b/src/main/java/com/iemr/common/identity/service/IdentityService.java @@ -811,8 +811,12 @@ public List searchBeneficiaryByVillageIdAndLastModifyDate(List public RMNCHBeneficiaryDetailsRmnch getRmnchDataByBenID(BigInteger benID) { + RMNCHBeneficiaryDetailsRmnch rmnchBeneficiaryDetailsRmnch = new RMNCHBeneficiaryDetailsRmnch(); - return rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benID); + if(!rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benID).isEmpty()){ + rmnchBeneficiaryDetailsRmnch = rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(benID).get(0); + } + return rmnchBeneficiaryDetailsRmnch; } public Long countBeneficiaryByVillageIdAndLastModifyDate(List villageIDs, Timestamp lastModifiedDate) { From bc39ce176de3f13899ec63b3752662b7ac2a8af6 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Thu, 4 Jun 2026 20:53:25 +0530 Subject: [PATCH 14/42] merge with release-3.6.2 --- .../iemr/common/identity/service/IdentityService.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/IdentityService.java b/src/main/java/com/iemr/common/identity/service/IdentityService.java index d0baad39..90e660b9 100644 --- a/src/main/java/com/iemr/common/identity/service/IdentityService.java +++ b/src/main/java/com/iemr/common/identity/service/IdentityService.java @@ -2003,6 +2003,7 @@ public List getBeneficiariesDeatilsByBenRegIdList(List Date: Fri, 12 Jun 2026 17:35:46 +0530 Subject: [PATCH 15/42] fix beneficiary save --- .../iemr/common/identity/controller/IdentityController.java | 4 +--- .../identity/service/rmnch/RmnchDataSyncServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/controller/IdentityController.java b/src/main/java/com/iemr/common/identity/controller/IdentityController.java index 74d9767b..fc894761 100644 --- a/src/main/java/com/iemr/common/identity/controller/IdentityController.java +++ b/src/main/java/com/iemr/common/identity/controller/IdentityController.java @@ -321,9 +321,7 @@ public String searchBeneficiaryByVillageIdAndLastModDate( @PostMapping("/getRmnchDataByBenRedID") - public ResponseEntity getRmnchDataByBenID( - @RequestBody BigInteger object) { - + public ResponseEntity getRmnchDataByBenID(@RequestBody BigInteger object) { try { RMNCHBeneficiaryDetailsRmnch data = svc.getRmnchDataByBenID(object); return ResponseEntity.ok(data); diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 07904279..d845d396 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -350,7 +350,7 @@ public String saveBeneficiaryDetailsAfterRegistration( } catch (Exception e) { logger.error("Error: ", e); - throw e; + return "Error save beneficiary in rmnch :"+e.getMessage(); } return "Saved RMNCH for beneficiaryID: " + beneficiaryID; From 3162f663e49005262c04b96139f4e557cd97471f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 12 Jun 2026 18:04:10 +0530 Subject: [PATCH 16/42] fix beneficiary save --- .../service/rmnch/RmnchDataSyncServiceImpl.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index d845d396..f88b095b 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -288,14 +288,18 @@ public String saveBeneficiaryDetailsAfterRegistration( // ✅ use find instead of get if(!rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)).isEmpty()){ - RMNCHBeneficiaryDetailsRmnch entity = - rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)).get(0); + List list = + rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)); + + RMNCHBeneficiaryDetailsRmnch entity; boolean isNew = false; - if (entity == null) { + if (list.isEmpty()) { entity = new RMNCHBeneficiaryDetailsRmnch(); isNew = true; + } else { + entity = list.get(0); } String createdBy = getString(requestObj, "createdBy", "system"); @@ -340,8 +344,10 @@ public String saveBeneficiaryDetailsAfterRegistration( )); } - rMNCHBeneficiaryDetailsRmnchRepo.save(entity); + RMNCHBeneficiaryDetailsRmnch saved = + rMNCHBeneficiaryDetailsRmnchRepo.save(entity); + logger.info("Saved Entity Id : {}", saved.getBeneficiaryDetails_RmnchId()); } From c1e2e2d9c54b42f22fc9c6991c4ba0ec70aada2c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 12 Jun 2026 18:15:16 +0530 Subject: [PATCH 17/42] fix beneficiary save --- .../common/identity/service/rmnch/RmnchDataSyncServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index f88b095b..cc8074da 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -277,7 +277,6 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { - @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public String saveBeneficiaryDetailsAfterRegistration( Long beneficiaryID, Long beneficiaryRegID, From 853ec9736cc495dbe7bb9430307d8eff7b4bd21e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Sat, 13 Jun 2026 10:17:01 +0530 Subject: [PATCH 18/42] fix beneficiary save --- .../rmnch/RmnchDataSyncServiceImpl.java | 68 +++++++++++-------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index cc8074da..b3b760d9 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -276,19 +276,27 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { } - + @Override public String saveBeneficiaryDetailsAfterRegistration( Long beneficiaryID, Long beneficiaryRegID, String comingRequest) { + logger.info("Method started. beneficiaryID={}, beneficiaryRegID={}", + beneficiaryID, beneficiaryRegID); + try { JsonObject requestObj = new Gson().fromJson(comingRequest, JsonObject.class); + logger.info("Request Parsed Successfully"); + + List list = + rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)); - // ✅ use find instead of get - if(!rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)).isEmpty()){ - List list = - rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)); + logger.info("Records found for RegID {} : {}", beneficiaryRegID, list.size()); + + if (!list.isEmpty()) { + + logger.info("Entering save/update block"); RMNCHBeneficiaryDetailsRmnch entity; @@ -297,65 +305,71 @@ public String saveBeneficiaryDetailsAfterRegistration( if (list.isEmpty()) { entity = new RMNCHBeneficiaryDetailsRmnch(); isNew = true; + logger.info("Creating new entity"); } else { entity = list.get(0); + logger.info("Updating existing entity. ID={}", + entity.getBeneficiaryDetails_RmnchId()); } String createdBy = getString(requestObj, "createdBy", "system"); + logger.info("createdBy={}", createdBy); entity.setBenficieryid(BigInteger.valueOf(beneficiaryID)); entity.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); - // ✅ Only set created fields for new record + logger.info("Basic details set"); + if (isNew) { entity.setCreatedBy(createdBy); entity.setCreatedDate(new Timestamp(System.currentTimeMillis())); + logger.info("Created fields set"); } else { entity.setUpdatedBy(createdBy); entity.setUpdatedDate(new Timestamp(System.currentTimeMillis())); + logger.info("Updated fields set"); } entity.setVanID(getInt(requestObj, "vanID", null)); entity.setParkingPlaceID(getInt(requestObj, "parkingPlaceID", null)); entity.setProviderServiceMapID(getInt(requestObj, "providerServiceMapID", null)); - entity.setGenderId(getInt(requestObj, "genderID", null)); - - entity.setReproductiveStatusId( - getInt(requestObj, "reproductiveStatusId", - getInt(requestObj, "maritalStatusID", null)) - ); - entity.setReproductiveStatus( - getString(requestObj, "reproductiveStatus", null) - ); + logger.info("Location details set"); entity.setFirstName(getString(requestObj, "firstName", null)); entity.setLastName(getString(requestObj, "lastName", null)); - entity.setFatherName(getString(requestObj, "fatherName", null)); - entity.setSpousename(getString(requestObj, "spouseName", null)); - entity.setMaritalstatusId(getInt(requestObj, "maritalStatusID", null)); - entity.setMaritalstatus(getString(requestObj, "maritalStatusName", null)); - // DOB + logger.info("Personal details set. FirstName={}, LastName={}", + entity.getFirstName(), entity.getLastName()); + if (requestObj.has("dOB") && !requestObj.get("dOB").isJsonNull()) { + logger.info("DOB found in request : {}", + requestObj.get("dOB").getAsString()); + entity.setDob(Timestamp.valueOf( - requestObj.get("dOB").getAsString().replace("T", " ").replace("Z", "") + requestObj.get("dOB").getAsString() + .replace("T", " ") + .replace("Z", "") )); } + logger.info("Before save"); + RMNCHBeneficiaryDetailsRmnch saved = rMNCHBeneficiaryDetailsRmnchRepo.save(entity); - logger.info("Saved Entity Id : {}", saved.getBeneficiaryDetails_RmnchId()); - } - + logger.info("After save. Saved ID={}", + saved.getBeneficiaryDetails_RmnchId()); + } else { + logger.info("No record found for beneficiaryRegID={}", beneficiaryRegID); + } - logger.info("Saved RMNCH for benRegID: " + beneficiaryRegID); + logger.info("Method completed successfully"); } catch (Exception e) { - logger.error("Error: ", e); - return "Error save beneficiary in rmnch :"+e.getMessage(); + logger.error("Exception occurred in saveBeneficiaryDetailsAfterRegistration", e); + return "Error save beneficiary in rmnch :" + e.getMessage(); } return "Saved RMNCH for beneficiaryID: " + beneficiaryID; From 52caaa1ecfed73177a0d9d0e0d6061608910e58b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Sat, 13 Jun 2026 10:25:29 +0530 Subject: [PATCH 19/42] fix beneficiary save --- .../rmnch/RmnchDataSyncServiceImpl.java | 153 ++++++++++-------- 1 file changed, 88 insertions(+), 65 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index b3b760d9..3348775e 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -277,6 +277,7 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { @Override + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public String saveBeneficiaryDetailsAfterRegistration( Long beneficiaryID, Long beneficiaryRegID, @@ -286,93 +287,115 @@ public String saveBeneficiaryDetailsAfterRegistration( beneficiaryID, beneficiaryRegID); try { + JsonObject requestObj = new Gson().fromJson(comingRequest, JsonObject.class); logger.info("Request Parsed Successfully"); List list = - rMNCHBeneficiaryDetailsRmnchRepo.getByRegID(BigInteger.valueOf(beneficiaryRegID)); + rMNCHBeneficiaryDetailsRmnchRepo.getByRegID( + BigInteger.valueOf(beneficiaryRegID)); logger.info("Records found for RegID {} : {}", beneficiaryRegID, list.size()); - if (!list.isEmpty()) { - - logger.info("Entering save/update block"); + RMNCHBeneficiaryDetailsRmnch entity; + boolean isNew = list.isEmpty(); - RMNCHBeneficiaryDetailsRmnch entity; - - boolean isNew = false; - - if (list.isEmpty()) { - entity = new RMNCHBeneficiaryDetailsRmnch(); - isNew = true; - logger.info("Creating new entity"); - } else { - entity = list.get(0); - logger.info("Updating existing entity. ID={}", - entity.getBeneficiaryDetails_RmnchId()); - } + if (isNew) { + entity = new RMNCHBeneficiaryDetailsRmnch(); + logger.info("Creating new RMNCH record"); + } else { + entity = list.get(0); + logger.info("Updating existing RMNCH record. ID={}", + entity.getBeneficiaryDetails_RmnchId()); + } - String createdBy = getString(requestObj, "createdBy", "system"); - logger.info("createdBy={}", createdBy); + String createdBy = getString(requestObj, "createdBy", "system"); - entity.setBenficieryid(BigInteger.valueOf(beneficiaryID)); - entity.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); + entity.setBenficieryid(BigInteger.valueOf(beneficiaryID)); + entity.setBenRegId(BigInteger.valueOf(beneficiaryRegID)); - logger.info("Basic details set"); + if (isNew) { + entity.setCreatedBy(createdBy); + entity.setCreatedDate(new Timestamp(System.currentTimeMillis())); + } else { + entity.setUpdatedBy(createdBy); + entity.setUpdatedDate(new Timestamp(System.currentTimeMillis())); + } - if (isNew) { - entity.setCreatedBy(createdBy); - entity.setCreatedDate(new Timestamp(System.currentTimeMillis())); - logger.info("Created fields set"); - } else { - entity.setUpdatedBy(createdBy); - entity.setUpdatedDate(new Timestamp(System.currentTimeMillis())); - logger.info("Updated fields set"); + entity.setVanID(getInt(requestObj, "vanID", null)); + entity.setParkingPlaceID(getInt(requestObj, "parkingPlaceID", null)); + entity.setProviderServiceMapID(getInt(requestObj, "providerServiceMapID", null)); + entity.setGenderId(getInt(requestObj, "genderID", null)); + + entity.setReproductiveStatusId( + getInt( + requestObj, + "reproductiveStatusId", + getInt(requestObj, "maritalStatusID", null) + ) + ); + + entity.setReproductiveStatus( + getString(requestObj, "reproductiveStatus", null) + ); + + entity.setFirstName(getString(requestObj, "firstName", null)); + entity.setLastName(getString(requestObj, "lastName", null)); + entity.setFatherName(getString(requestObj, "fatherName", null)); + entity.setSpousename(getString(requestObj, "spouseName", null)); + + entity.setMaritalstatusId( + getInt(requestObj, "maritalStatusID", null) + ); + + entity.setMaritalstatus( + getString(requestObj, "maritalStatusName", null) + ); + + // DOB + if (requestObj.has("dOB") + && !requestObj.get("dOB").isJsonNull() + && requestObj.get("dOB").getAsString().trim().length() > 0) { + + try { + entity.setDob( + Timestamp.valueOf( + requestObj.get("dOB") + .getAsString() + .replace("T", " ") + .replace("Z", "") + ) + ); + + logger.info("DOB set successfully"); + + } catch (Exception ex) { + logger.error("Invalid DOB format : {}", + requestObj.get("dOB").getAsString(), ex); } + } - entity.setVanID(getInt(requestObj, "vanID", null)); - entity.setParkingPlaceID(getInt(requestObj, "parkingPlaceID", null)); - entity.setProviderServiceMapID(getInt(requestObj, "providerServiceMapID", null)); - - logger.info("Location details set"); - - entity.setFirstName(getString(requestObj, "firstName", null)); - entity.setLastName(getString(requestObj, "lastName", null)); - - logger.info("Personal details set. FirstName={}, LastName={}", - entity.getFirstName(), entity.getLastName()); - - if (requestObj.has("dOB") && !requestObj.get("dOB").isJsonNull()) { - logger.info("DOB found in request : {}", - requestObj.get("dOB").getAsString()); + logger.info("Before save"); - entity.setDob(Timestamp.valueOf( - requestObj.get("dOB").getAsString() - .replace("T", " ") - .replace("Z", "") - )); - } + RMNCHBeneficiaryDetailsRmnch saved = + rMNCHBeneficiaryDetailsRmnchRepo.save(entity); - logger.info("Before save"); + logger.info("After save. Saved ID={}", + saved.getBeneficiaryDetails_RmnchId()); - RMNCHBeneficiaryDetailsRmnch saved = - rMNCHBeneficiaryDetailsRmnchRepo.save(entity); + logger.info("Saved RMNCH for benRegID={}", beneficiaryRegID); - logger.info("After save. Saved ID={}", - saved.getBeneficiaryDetails_RmnchId()); + return "Saved RMNCH for beneficiaryID: " + beneficiaryID; - } else { - logger.info("No record found for beneficiaryRegID={}", beneficiaryRegID); - } + } catch (Exception e) { - logger.info("Method completed successfully"); + logger.error( + "Exception occurred in saveBeneficiaryDetailsAfterRegistration", + e + ); - } catch (Exception e) { - logger.error("Exception occurred in saveBeneficiaryDetailsAfterRegistration", e); - return "Error save beneficiary in rmnch :" + e.getMessage(); + return "Error save beneficiary in rmnch : " + e.getMessage(); } - - return "Saved RMNCH for beneficiaryID: " + beneficiaryID; } private String getString(JsonObject obj, String key, String defaultVal) { return (obj.has(key) && !obj.get(key).isJsonNull()) From d75ed23bbc180fbd3ca56fcf06c6d41f125b62ce Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 16 Jun 2026 16:23:37 +0530 Subject: [PATCH 20/42] fix beneficiary save --- .../repo/rmnch/RMNCHBenDetailsRepo.java | 18 +++++++--- .../rmnch/RmnchDataSyncServiceImpl.java | 34 +++++++++++-------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHBenDetailsRepo.java b/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHBenDetailsRepo.java index 104fe902..27c7a445 100644 --- a/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHBenDetailsRepo.java +++ b/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHBenDetailsRepo.java @@ -22,7 +22,9 @@ package com.iemr.common.identity.repo.rmnch; import java.math.BigInteger; +import java.util.List; +import io.swagger.v3.oas.annotations.info.License; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; @@ -35,8 +37,16 @@ public interface RMNCHBenDetailsRepo extends CrudRepository getByBenRegID( + @Param("beneficiaryRegID") BigInteger beneficiaryRegID); } diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 3348775e..ca0807fc 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -172,22 +172,25 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { } obj.setRelatedBeneficiaryIdsDB(sb.toString()); } - RMNCHMBeneficiarydetail rmnchmBeneficiarydetail = - rMNCHBenDetailsRepo.getByBenRegID(obj.getBenRegId()); - if (rmnchmBeneficiarydetail != null) { - rmnchmBeneficiarydetail.setFirstName(obj.getFirstName()); - rmnchmBeneficiarydetail.setLastName(obj.getLastName()); - rmnchmBeneficiarydetail.setFatherName(obj.getFatherName()); - rmnchmBeneficiarydetail.setMotherName(obj.getMotherName()); - rmnchmBeneficiarydetail.setDob(obj.getDob()); - rmnchmBeneficiarydetail.setSpousename(obj.getSpousename()); - rmnchmBeneficiarydetail.setGender(obj.getGender()); - rmnchmBeneficiarydetail.setGenderId(obj.getGenderId()); - rmnchmBeneficiarydetail.setMaritalstatus(obj.getMaritalstatus()); - rmnchmBeneficiarydetail.setMaritalstatusId(obj.getMaritalstatusId()); - benDetailsList.add(rmnchmBeneficiarydetail); + if(!rMNCHBenDetailsRepo.getByBenRegID(obj.getBenRegId()).isEmpty()){ + RMNCHMBeneficiarydetail rmnchmBeneficiarydetail = + rMNCHBenDetailsRepo.getByBenRegID(obj.getBenRegId()).get(0); + if (rmnchmBeneficiarydetail != null) { + rmnchmBeneficiarydetail.setFirstName(obj.getFirstName()); + rmnchmBeneficiarydetail.setLastName(obj.getLastName()); + rmnchmBeneficiarydetail.setFatherName(obj.getFatherName()); + rmnchmBeneficiarydetail.setMotherName(obj.getMotherName()); + rmnchmBeneficiarydetail.setDob(obj.getDob()); + rmnchmBeneficiarydetail.setSpousename(obj.getSpousename()); + rmnchmBeneficiarydetail.setGender(obj.getGender()); + rmnchmBeneficiarydetail.setGenderId(obj.getGenderId()); + rmnchmBeneficiarydetail.setMaritalstatus(obj.getMaritalstatus()); + rmnchmBeneficiarydetail.setMaritalstatusId(obj.getMaritalstatusId()); + benDetailsList.add(rmnchmBeneficiarydetail); + } } + } benDetailsExtraList = (ArrayList) rMNCHBeneficiaryDetailsRmnchRepo @@ -264,8 +267,11 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { } catch ( Exception e) { + logger.error("Full Exception", e); + throw new Exception(e); // ✅ original exception wrap karo + } resultMap.put("beneficiaryDetails", beneficiaryDetailsIds); resultMap.put("bornBirthDeatils", bornBirthDeatilsIds); From 028e1b771466e9855c4ddd812c4495a525edd6a8 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 16 Jun 2026 16:33:02 +0530 Subject: [PATCH 21/42] fix beneficiary save --- .../identity/repo/rmnch/RMNCHHouseHoldDetailsRepo.java | 6 ++++-- .../identity/service/rmnch/RmnchDataSyncServiceImpl.java | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHHouseHoldDetailsRepo.java b/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHHouseHoldDetailsRepo.java index 4aed3c87..76490cbd 100644 --- a/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHHouseHoldDetailsRepo.java +++ b/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHHouseHoldDetailsRepo.java @@ -28,11 +28,13 @@ import com.iemr.common.identity.data.rmnch.RMNCHHouseHoldDetails; +import java.util.List; + @Repository public interface RMNCHHouseHoldDetailsRepo extends CrudRepository { @Query(" SELECT t FROM RMNCHHouseHoldDetails t WHERE t.id = :vanSerialNo AND t.VanID = :vanID") public RMNCHHouseHoldDetails getByIdAndVanID(@Param("vanSerialNo") long vanSerialNo, @Param("vanID") int vanID); - @Query(" SELECT t FROM RMNCHHouseHoldDetails t WHERE t.houseoldId =:houseoldId ") - public RMNCHHouseHoldDetails getByHouseHoldID(@Param("houseoldId") long houseoldId); + @Query("SELECT t FROM RMNCHHouseHoldDetails t WHERE t.houseoldId = :houseoldId") + List getByHouseHoldID(@Param("houseoldId") long houseoldId); } diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index ca0807fc..708bb918 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -248,7 +248,7 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { for (RMNCHHouseHoldDetails obj : houseHoldList) { RMNCHHouseHoldDetails temp = rMNCHHouseHoldDetailsRepo - .getByHouseHoldID(obj.getHouseoldId()); + .getByHouseHoldID(obj.getHouseoldId()).get(0); if (temp != null) obj.setHouseHoldDetailsId(temp.getHouseHoldDetailsId()); } @@ -583,7 +583,7 @@ private String getMappingsForAddressIDs(List addressLi // 20-09-2021,end if (benDetailsRMNCHOBJ != null && benDetailsRMNCHOBJ.getHouseoldId() != null) benHouseHoldRMNCHROBJ = rMNCHHouseHoldDetailsRepo - .getByHouseHoldID(benDetailsRMNCHOBJ.getHouseoldId()); + .getByHouseHoldID(benDetailsRMNCHOBJ.getHouseoldId()).get(0); } if (benDetailsRMNCHOBJ == null) From 6258dae8119c3db8bff1ce4c51a32971a7c1a06b Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Tue, 16 Jun 2026 16:43:30 +0530 Subject: [PATCH 22/42] fix beneficiary save --- .../service/rmnch/RmnchDataSyncServiceImpl.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 708bb918..ca85397f 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -247,10 +247,14 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { List houseHoldList = Arrays.asList(objArr3); for (RMNCHHouseHoldDetails obj : houseHoldList) { - RMNCHHouseHoldDetails temp = rMNCHHouseHoldDetailsRepo - .getByHouseHoldID(obj.getHouseoldId()).get(0); - if (temp != null) - obj.setHouseHoldDetailsId(temp.getHouseHoldDetailsId()); + if(!rMNCHHouseHoldDetailsRepo + .getByHouseHoldID(obj.getHouseoldId()).isEmpty()){ + RMNCHHouseHoldDetails temp = rMNCHHouseHoldDetailsRepo + .getByHouseHoldID(obj.getHouseoldId()).get(0); + if (temp != null) + obj.setHouseHoldDetailsId(temp.getHouseHoldDetailsId()); + } + } houseHoldList = (ArrayList) rMNCHHouseHoldDetailsRepo .saveAll(houseHoldList); From ee770954722ab31b6ee27378f941ac1a6df77f05 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 08:22:46 +0530 Subject: [PATCH 23/42] change release version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c3b57f1c..9eda8258 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.iemr.common.identity identity-api - 3.6.2 + 3.9.0 war From 8d83a9af95d3280c080d3060bdadcaf94aedae34 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 14:03:20 +0530 Subject: [PATCH 24/42] save abha id in health maping with beneficiaryID --- .../rmnch/RMNCHMobileAppController.java | 4 +- .../service/rmnch/RmnchDataSyncService.java | 2 +- .../rmnch/RmnchDataSyncServiceImpl.java | 67 +++++++++++++++++-- src/main/resources/application.properties | 1 + 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java index cbb91cce..5552e90f 100644 --- a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java +++ b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java @@ -59,11 +59,11 @@ public class RMNCHMobileAppController { @PostMapping(value = "/syncDataToAmrit", consumes = "application/json", produces = "application/json") @Operation(summary = "Sync data to AMRIT for already regestered beneficiary with AMRIT beneficiary id ") - public String syncDataToAmrit(@RequestBody String requestOBJ) { + public String syncDataToAmrit(@RequestBody String requestOBJ,@RequestHeader(value = "Authorization") String authorization) { OutputResponse response = new OutputResponse(); try { if (requestOBJ != null) { - String s = rmnchDataSyncService.syncDataToAmrit(requestOBJ); + String s = rmnchDataSyncService.syncDataToAmrit(requestOBJ,authorization); response.setResponse(s); } else response.setError(5000, "Invalid/NULL request obj"); diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java index 845e79f9..7bbcb316 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncService.java @@ -22,7 +22,7 @@ package com.iemr.common.identity.service.rmnch; public interface RmnchDataSyncService { - public String syncDataToAmrit(String requestOBJ) throws Exception; + public String syncDataToAmrit(String requestOBJ, String authorization) throws Exception; public String saveBeneficiaryDetailsAfterRegistration( Long beneficiaryID, Long beneficiaryRegID, diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index a62450ed..d2284ee5 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -33,8 +33,6 @@ import java.util.Map; import java.util.regex.Pattern; -import com.iemr.common.identity.utils.OutputResponse; -import io.swagger.v3.oas.annotations.Operation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -78,8 +76,6 @@ import com.iemr.common.identity.utils.exception.IEMRException; import com.iemr.common.identity.utils.http.HttpUtils; import com.iemr.common.identity.utils.mapper.InputMapper; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; @Service @Qualifier("rmnchServiceImpl") @@ -115,7 +111,8 @@ public class RmnchDataSyncServiceImpl implements RmnchDataSyncService { private RMNCHMBenRegIdMapRepo rMNCHMBenRegIdMapRepo; @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) @Override - public String syncDataToAmrit(String requestOBJ) throws Exception { + public String syncDataToAmrit(String requestOBJ, String authorization) throws Exception { + Map resultMap = new HashMap(); @@ -133,6 +130,8 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { // other tables data saving // ben details RMNCH extra fields details + logger.info("Request object of syncDataToAmrit: "+jsnOBJ); + BigInteger benRegID = null; @@ -187,6 +186,14 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { rmnchmBeneficiarydetail.setMaritalstatus(obj.getMaritalstatus()); rmnchmBeneficiarydetail.setMaritalstatusId(obj.getMaritalstatusId()); benDetailsList.add(rmnchmBeneficiarydetail); + if (jsnOBJ.has("abhaId") && !jsnOBJ.get("abhaId").isJsonNull()) { + String abhaId = jsnOBJ.get("abhaId").getAsString(); + if(!abhaId.isEmpty() || abhaId!=null){ + mapHealthIDToBeneficiary(authorization,rmnchmBeneficiarydetail.getBenRegId().longValue(),rmnchmBeneficiarydetail.getBenficieryid().longValue(),abhaId,rmnchmBeneficiarydetail.getCreatedBy(),rmnchmBeneficiarydetail.getFirstName(),rmnchmBeneficiarydetail.getLastName(),rmnchmBeneficiarydetail.getDob().toString(),rmnchmBeneficiarydetail.getProviderServiceMapID()); + + } + } + } } @@ -285,6 +292,56 @@ public String syncDataToAmrit(String requestOBJ) throws Exception { return new Gson().toJson(resultMap); } + public String mapHealthIDToBeneficiary(String authorization, + Long benRegID, + Long beneficiaryID, + String abhaId, + String createdBy,String firstName,String lastName,String dob,Integer providerServiceMapId) { + try { + Map requestMap = new HashMap<>(); + + requestMap.put("beneficiaryRegID", benRegID); + requestMap.put("beneficiaryID", beneficiaryID); + requestMap.put("healthIdNumber", abhaId); + + requestMap.put("createdBy", createdBy); + requestMap.put("providerServiceMapId", providerServiceMapId); + requestMap.put("isNew", false); + + // ABHA Profile + Map abhaProfile = new HashMap<>(); + abhaProfile.put("ABHANumber", abhaId); + + List phrAddress = new ArrayList<>(); + phrAddress.add(abhaId + "@abdm"); + + abhaProfile.put("phrAddress", phrAddress); + abhaProfile.put("firstName", firstName); + abhaProfile.put("middleName", ""); + abhaProfile.put("lastName", lastName); + abhaProfile.put("dob", dob); + + requestMap.put("ABHAProfile", abhaProfile); + + HttpUtils utils = new HttpUtils(); + + HashMap header = new HashMap<>(); + header.put("Authorization", authorization); + + String responseStr = utils.post( + ConfigProperties.getPropertyByName("fhir-url") + + ConfigProperties.getPropertyByName("mapHealthIDToBeneficiary"), + new Gson().toJson(requestMap), + header); + logger.info("Save abha id in health mapping:"+responseStr.toString()); + return responseStr; + }catch (Exception e){ + logger.info("Error Save Health Id"); + return "Error Save Health Id: "+e.getMessage(); + } + + } + @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 12be1b44..79ba181f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -148,6 +148,7 @@ spring.jpa.properties.hibernate.show_sql=false door-to-door-page-size=2 get-HRP-Status=ANC/getHRPStatus getHealthID=healthID/getBenhealthID +mapHealthIDToBeneficiary=healthIDRecord/mapHealthIDToBeneficiary spring.main.allow-bean-definition-overriding=true spring.main.allow-circular-references=true From 3b7dd5200937faa4a7bf965933dcf0b7d5c6e111 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 16:27:15 +0530 Subject: [PATCH 25/42] abha id add in entity class --- .../identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java | 3 +++ .../identity/data/rmnch/RMNCHMBeneficiarydetail.java | 4 ++++ .../identity/service/rmnch/RmnchDataSyncServiceImpl.java | 7 ++----- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java index 4cab210c..e403b3d7 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java @@ -550,4 +550,7 @@ public class RMNCHBeneficiaryDetailsRmnch { @Expose private Boolean isDeactivate; + @Expose + @Transient + private String abhaId; } diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java index 397c5a66..d9221675 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java @@ -214,4 +214,8 @@ public class RMNCHMBeneficiarydetail { @Expose @Transient private Integer ProviderServiceMapID; + + @Expose + @Transient + private String abhaId; } \ No newline at end of file diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index d2284ee5..27ca8739 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -186,12 +186,9 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex rmnchmBeneficiarydetail.setMaritalstatus(obj.getMaritalstatus()); rmnchmBeneficiarydetail.setMaritalstatusId(obj.getMaritalstatusId()); benDetailsList.add(rmnchmBeneficiarydetail); - if (jsnOBJ.has("abhaId") && !jsnOBJ.get("abhaId").isJsonNull()) { - String abhaId = jsnOBJ.get("abhaId").getAsString(); - if(!abhaId.isEmpty() || abhaId!=null){ - mapHealthIDToBeneficiary(authorization,rmnchmBeneficiarydetail.getBenRegId().longValue(),rmnchmBeneficiarydetail.getBenficieryid().longValue(),abhaId,rmnchmBeneficiarydetail.getCreatedBy(),rmnchmBeneficiarydetail.getFirstName(),rmnchmBeneficiarydetail.getLastName(),rmnchmBeneficiarydetail.getDob().toString(),rmnchmBeneficiarydetail.getProviderServiceMapID()); + if (obj.getAbhaId()!=null && !obj.getAbhaId().isEmpty()) { + mapHealthIDToBeneficiary(authorization,obj.getBenRegId().longValue(),obj.getBenficieryid().longValue(),obj.getAbhaId(),obj.getCreatedBy(),obj.getFirstName(),obj.getLastName(),obj.getDob().toString(),obj.getProviderServiceMapID()); - } } } From 1d8dbe75ce20d33ac2f192e21cb1c399cbd35d9d Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 16:37:16 +0530 Subject: [PATCH 26/42] abha id add in entity class --- .../common/identity/service/rmnch/RmnchDataSyncServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 27ca8739..962c31c8 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -333,7 +333,7 @@ public String mapHealthIDToBeneficiary(String authorization, logger.info("Save abha id in health mapping:"+responseStr.toString()); return responseStr; }catch (Exception e){ - logger.info("Error Save Health Id"); + logger.info("Error Save Health Id"+e); return "Error Save Health Id: "+e.getMessage(); } From 1801efed23e349b400fe1da51cfafb42c565764c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 17:31:48 +0530 Subject: [PATCH 27/42] abha id add in entity class --- .../identity/service/rmnch/RmnchDataSyncServiceImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 962c31c8..d5dd5a1b 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -109,6 +109,9 @@ public class RmnchDataSyncServiceImpl implements RmnchDataSyncService { private RMNCHBenContactRepo rMNCHBenContactRepo; @Autowired private RMNCHMBenRegIdMapRepo rMNCHMBenRegIdMapRepo; + + @Value("${fhir-url}") + private String fhirUrl; @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) @Override public String syncDataToAmrit(String requestOBJ, String authorization) throws Exception { @@ -326,8 +329,7 @@ public String mapHealthIDToBeneficiary(String authorization, header.put("Authorization", authorization); String responseStr = utils.post( - ConfigProperties.getPropertyByName("fhir-url") - + ConfigProperties.getPropertyByName("mapHealthIDToBeneficiary"), + fhirUrl+ConfigProperties.getPropertyByName("mapHealthIDToBeneficiary"), new Gson().toJson(requestMap), header); logger.info("Save abha id in health mapping:"+responseStr.toString()); From 594ab594c19898d10ea6c75e8a612e99d027de6a Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 17:43:32 +0530 Subject: [PATCH 28/42] abha id add in entity class --- .../identity/controller/rmnch/RMNCHMobileAppController.java | 2 +- .../common/identity/service/rmnch/RmnchDataSyncServiceImpl.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java index 5552e90f..f8a8957f 100644 --- a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java +++ b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java @@ -59,7 +59,7 @@ public class RMNCHMobileAppController { @PostMapping(value = "/syncDataToAmrit", consumes = "application/json", produces = "application/json") @Operation(summary = "Sync data to AMRIT for already regestered beneficiary with AMRIT beneficiary id ") - public String syncDataToAmrit(@RequestBody String requestOBJ,@RequestHeader(value = "Authorization") String authorization) { + public String syncDataToAmrit(@RequestBody String requestOBJ,@RequestHeader(value = "jwttoken") String authorization) { OutputResponse response = new OutputResponse(); try { if (requestOBJ != null) { diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index d5dd5a1b..dffbf5df 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -328,6 +328,7 @@ public String mapHealthIDToBeneficiary(String authorization, HashMap header = new HashMap<>(); header.put("Authorization", authorization); + String responseStr = utils.post( fhirUrl+ConfigProperties.getPropertyByName("mapHealthIDToBeneficiary"), new Gson().toJson(requestMap), From ec021c4a27c03aa0406a141264a168af92c85b5e Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 17:48:36 +0530 Subject: [PATCH 29/42] abha id add in entity class --- .../common/identity/service/rmnch/RmnchDataSyncServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index dffbf5df..c7f9e795 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -299,6 +299,7 @@ public String mapHealthIDToBeneficiary(String authorization, String createdBy,String firstName,String lastName,String dob,Integer providerServiceMapId) { try { Map requestMap = new HashMap<>(); + logger.info("authorization:"+authorization); requestMap.put("beneficiaryRegID", benRegID); requestMap.put("beneficiaryID", beneficiaryID); From 5a83005d1895e31443170e7d47adffd24cfef1b3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 17:59:41 +0530 Subject: [PATCH 30/42] abha id add in entity class --- .../rmnch/RmnchDataSyncServiceImpl.java | 61 +++++++++++++++---- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index c7f9e795..f73a2d98 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -40,6 +40,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -76,6 +77,8 @@ import com.iemr.common.identity.utils.exception.IEMRException; import com.iemr.common.identity.utils.http.HttpUtils; import com.iemr.common.identity.utils.mapper.InputMapper; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; @Service @Qualifier("rmnchServiceImpl") @@ -298,8 +301,11 @@ public String mapHealthIDToBeneficiary(String authorization, String abhaId, String createdBy,String firstName,String lastName,String dob,Integer providerServiceMapId) { try { + RestTemplate restTemplate = new RestTemplate(); + + logger.info("Authorization Token : {}", authorization); + Map requestMap = new HashMap<>(); - logger.info("authorization:"+authorization); requestMap.put("beneficiaryRegID", benRegID); requestMap.put("beneficiaryID", beneficiaryID); @@ -324,21 +330,50 @@ public String mapHealthIDToBeneficiary(String authorization, requestMap.put("ABHAProfile", abhaProfile); - HttpUtils utils = new HttpUtils(); + String requestBody = new Gson().toJson(requestMap); + + String url = fhirUrl + + ConfigProperties.getPropertyByName("mapHealthIDToBeneficiary"); + + logger.info("Calling URL : {}", url); + logger.info("Request Body : {}", requestBody); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + // Agar token me Bearer nahi aa raha hai + if (authorization != null && !authorization.startsWith("Bearer ")) { + authorization = "Bearer " + authorization; + } + + headers.set("Authorization", authorization); + + HttpEntity entity = + new HttpEntity<>(requestBody, headers); + + ResponseEntity response = restTemplate.exchange( + url, + HttpMethod.POST, + entity, + String.class + ); + + logger.info("ABHA Mapping Response : {}", response.getBody()); + + return response.getBody(); + + } catch (HttpClientErrorException e) { + + logger.error("HTTP Error Status : {}", e.getStatusCode()); + logger.error("HTTP Error Response : {}", e.getResponseBodyAsString(), e); + + return "HTTP Error : " + e.getStatusCode(); - HashMap header = new HashMap<>(); - header.put("Authorization", authorization); + } catch (Exception e) { + logger.error("Error while saving Health ID Mapping", e); - String responseStr = utils.post( - fhirUrl+ConfigProperties.getPropertyByName("mapHealthIDToBeneficiary"), - new Gson().toJson(requestMap), - header); - logger.info("Save abha id in health mapping:"+responseStr.toString()); - return responseStr; - }catch (Exception e){ - logger.info("Error Save Health Id"+e); - return "Error Save Health Id: "+e.getMessage(); + return "Error Save Health Id : " + e.getMessage(); } } From 32db7e19a23ca42fc02d06830a8ab14d20a84452 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 18:18:37 +0530 Subject: [PATCH 31/42] abha id add in entity class --- .../identity/service/rmnch/RmnchDataSyncServiceImpl.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index f73a2d98..131d55f4 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -340,13 +340,9 @@ public String mapHealthIDToBeneficiary(String authorization, HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); - // Agar token me Bearer nahi aa raha hai - if (authorization != null && !authorization.startsWith("Bearer ")) { - authorization = "Bearer " + authorization; - } - headers.set("Authorization", authorization); + headers.set("Jwttoken", authorization); HttpEntity entity = new HttpEntity<>(requestBody, headers); From a90fe132d315f1822b9fac9e9affcb5b05acfc0c Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 17 Jun 2026 18:32:16 +0530 Subject: [PATCH 32/42] abha id add in entity class --- .../service/rmnch/RmnchDataSyncServiceImpl.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 131d55f4..e11aba38 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -24,6 +24,7 @@ import java.math.BigInteger; import java.sql.Date; import java.sql.Timestamp; +import java.text.SimpleDateFormat; import java.time.Period; import java.util.ArrayList; import java.util.Arrays; @@ -302,7 +303,17 @@ public String mapHealthIDToBeneficiary(String authorization, String createdBy,String firstName,String lastName,String dob,Integer providerServiceMapId) { try { RestTemplate restTemplate = new RestTemplate(); - + String formattedDob = dob; + + try { + if (dob != null && dob.contains(" ")) { + Timestamp timestamp = Timestamp.valueOf(dob); + formattedDob = new SimpleDateFormat("dd-MM-yyyy") + .format(timestamp); + } + } catch (Exception ex) { + logger.warn("DOB format conversion failed, sending original DOB : {}", dob); + } logger.info("Authorization Token : {}", authorization); Map requestMap = new HashMap<>(); @@ -326,7 +337,8 @@ public String mapHealthIDToBeneficiary(String authorization, abhaProfile.put("firstName", firstName); abhaProfile.put("middleName", ""); abhaProfile.put("lastName", lastName); - abhaProfile.put("dob", dob); + abhaProfile.put("dob", formattedDob); + requestMap.put("ABHAProfile", abhaProfile); From dc2ad36aad93f0726c8aa065121b14cc52d6df0a Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Mon, 22 Jun 2026 18:05:28 +0530 Subject: [PATCH 33/42] abha id add in entity class --- .../identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java | 4 ++++ .../common/identity/data/rmnch/RMNCHMBeneficiarydetail.java | 4 ++++ .../identity/service/rmnch/RmnchDataSyncServiceImpl.java | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java index e403b3d7..1fb1b66d 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java @@ -553,4 +553,8 @@ public class RMNCHBeneficiaryDetailsRmnch { @Expose @Transient private String abhaId; + + @Expose + @Transient + private String familyId; } diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java index d9221675..44f15679 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java @@ -218,4 +218,8 @@ public class RMNCHMBeneficiarydetail { @Expose @Transient private String abhaId; + + @Expose + @Column(name = "familyid") + private String familyId; } \ No newline at end of file diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index e11aba38..0b469009 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -192,6 +192,10 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex rmnchmBeneficiarydetail.setGenderId(obj.getGenderId()); rmnchmBeneficiarydetail.setMaritalstatus(obj.getMaritalstatus()); rmnchmBeneficiarydetail.setMaritalstatusId(obj.getMaritalstatusId()); + if(obj.getFamilyId()!=null && !obj.getFamilyId().isEmpty()){ + rmnchmBeneficiarydetail.setFamilyId(obj.getFamilyId()); + + } benDetailsList.add(rmnchmBeneficiarydetail); if (obj.getAbhaId()!=null && !obj.getAbhaId().isEmpty()) { mapHealthIDToBeneficiary(authorization,obj.getBenRegId().longValue(),obj.getBenficieryid().longValue(),obj.getAbhaId(),obj.getCreatedBy(),obj.getFirstName(),obj.getLastName(),obj.getDob().toString(),obj.getProviderServiceMapID()); From f1ec9716626d6e143326918f605f7786bee5959a Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 24 Jun 2026 13:55:16 +0530 Subject: [PATCH 34/42] fixed issue of Query did not return a unique result: 2 results were returned in RMNCH --- .../common/identity/service/rmnch/RmnchDataSyncServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 0b469009..f82abf3d 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -356,7 +356,6 @@ public String mapHealthIDToBeneficiary(String authorization, HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); - // Agar token me Bearer nahi aa raha hai headers.set("Jwttoken", authorization); From ad138d7da109609aeeec4be194e514f15214624f Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 24 Jun 2026 14:25:58 +0530 Subject: [PATCH 35/42] fixed issue of Query did not return a unique result: 2 results were returned in RMNCH --- .../repo/rmnch/RMNCHBornBirthDetailsRepo.java | 3 ++- .../repo/rmnch/RMNCHCBACDetailsRepo.java | 2 +- .../rmnch/RmnchDataSyncServiceImpl.java | 27 +++++++++++++------ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHBornBirthDetailsRepo.java b/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHBornBirthDetailsRepo.java index 2af4d5b7..21488700 100644 --- a/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHBornBirthDetailsRepo.java +++ b/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHBornBirthDetailsRepo.java @@ -22,6 +22,7 @@ package com.iemr.common.identity.repo.rmnch; import java.math.BigInteger; +import java.util.List; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; @@ -36,5 +37,5 @@ public interface RMNCHBornBirthDetailsRepo extends CrudRepository getByRegID(@Param("benRegID") BigInteger benRegID); } diff --git a/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHCBACDetailsRepo.java b/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHCBACDetailsRepo.java index 49fb4697..95e452b4 100644 --- a/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHCBACDetailsRepo.java +++ b/src/main/java/com/iemr/common/identity/repo/rmnch/RMNCHCBACDetailsRepo.java @@ -37,7 +37,7 @@ public interface RMNCHCBACDetailsRepo extends CrudRepository getByRegID(@Param("benRegID") BigInteger benRegID); @Query(value = "select beneficiary_visit_code,visit_category from db_iemr.i_ben_flow_outreach where beneficiary_reg_id=:benRegID AND beneficiary_visit_code is not null AND visit_category is not null order by created_date desc limit 1", nativeQuery = true) public List getVisitDetailsbyRegID(@Param("benRegID") Long benRegID); diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index f82abf3d..0c89c170 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -223,9 +223,12 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex for (RMNCHBornBirthDetails obj : bornBirthList) { benRegID = rMNCHMBenRegIdMapRepo.getRegID(obj.getBenficieryid()); obj.setBenRegId(benRegID); - RMNCHBornBirthDetails temp = rMNCHBornBirthDetailsRepo.getByRegID(benRegID); - if (temp != null) - obj.setBornBirthDeatilsId(temp.getBornBirthDeatilsId()); + if(!rMNCHBornBirthDetailsRepo.getByRegID(benRegID).isEmpty()){ + RMNCHBornBirthDetails temp = rMNCHBornBirthDetailsRepo.getByRegID(benRegID).get(0); + if (temp != null) + obj.setBornBirthDeatilsId(temp.getBornBirthDeatilsId()); + } + } bornBirthList = (ArrayList) rMNCHBornBirthDetailsRepo .saveAll(bornBirthList); @@ -246,9 +249,12 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex obj.setConfirmed_tb("Not checked"); obj.setConfirmed_ncd_diseases("Not checked"); obj.setDiagnosis_status("pending"); - RMNCHCBACdetails temp = rMNCHCBACDetailsRepo.getByRegID(benRegID); - if (temp != null) - obj.setCBACDetailsid(temp.getCBACDetailsid()); + if(!rMNCHCBACDetailsRepo.getByRegID(benRegID).isEmpty()){ + RMNCHCBACdetails temp = rMNCHCBACDetailsRepo.getByRegID(benRegID).get(0); + if (temp != null) + obj.setCBACDetailsid(temp.getCBACDetailsid()); + } + } cbacList = (ArrayList) rMNCHCBACDetailsRepo.saveAll(cbacList); @@ -666,10 +672,15 @@ private String getMappingsForAddressIDs(List addressLi benDetailsRMNCHOBJ = rMNCHBeneficiaryDetailsRmnchRepo .getByRegID(m.getBenRegId()).get(0); } + if(!rMNCHBornBirthDetailsRepo.getByRegID(m.getBenRegId()).isEmpty()){ + benBotnBirthRMNCHROBJ = rMNCHBornBirthDetailsRepo.getByRegID(m.getBenRegId()).get(0); + + } + if(! rMNCHCBACDetailsRepo.getByRegID(m.getBenRegId()).isEmpty()){ + benCABCRMNCHROBJ = rMNCHCBACDetailsRepo.getByRegID(m.getBenRegId()).get(0); - benBotnBirthRMNCHROBJ = rMNCHBornBirthDetailsRepo.getByRegID(m.getBenRegId()); + } - benCABCRMNCHROBJ = rMNCHCBACDetailsRepo.getByRegID(m.getBenRegId()); // 20-09-2021,start NcdTbHrpData res = getHRP_NCD_TB_SuspectedStatus(m.getBenRegId().longValue(), authorisation, benDetailsOBJ); From 83b604673d9b835e2d6e288188efa2cac2d0c2be Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 3 Jul 2026 12:04:20 +0530 Subject: [PATCH 36/42] attach logger in response --- .../rmnch/RMNCHMobileAppController.java | 5 +++++ .../service/rmnch/RmnchDataSyncServiceImpl.java | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java index f8a8957f..deada381 100644 --- a/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java +++ b/src/main/java/com/iemr/common/identity/controller/rmnch/RMNCHMobileAppController.java @@ -63,8 +63,13 @@ public String syncDataToAmrit(@RequestBody String requestOBJ,@RequestHeader(valu OutputResponse response = new OutputResponse(); try { if (requestOBJ != null) { + String s = rmnchDataSyncService.syncDataToAmrit(requestOBJ,authorization); + logger.info("syncDataToAmrit Response: {}", s); + response.setResponse(s); + + logger.info(" syncDataToAmrit Final API Response: {}", response.toString()); } else response.setError(5000, "Invalid/NULL request obj"); } catch (Exception e) { diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 0c89c170..3bbd6b09 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -306,6 +306,21 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex return new Gson().toJson(resultMap); } + /** + * Splits a list into sub-lists (batches) of the given size. + * Last batch may contain fewer elements. + */ + private List> partitionList(List list, int batchSize) { + List> batches = new ArrayList<>(); + if (list == null || list.isEmpty()) { + return batches; + } + for (int i = 0; i < list.size(); i += batchSize) { + batches.add(new ArrayList<>(list.subList(i, Math.min(i + batchSize, list.size())))); + } + return batches; + } + public String mapHealthIDToBeneficiary(String authorization, Long benRegID, Long beneficiaryID, From 5696472ed7a6ce42c5308c8adc6013e6065e055e Mon Sep 17 00:00:00 2001 From: Vanitha S <116701245+vanitha1822@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:58:09 +0530 Subject: [PATCH 37/42] Fix the Elasticsearch Health Status (#173) * fix: authenticate elasticsearch health probes against secured cluster The /health Elasticsearch client was built without credentials, so probes against a security-enabled cluster returned 401 and reported ES DOWN (forcing overall status DOWN) even though ES was healthy. Inject elasticsearch.username/ password and attach a BasicCredentialsProvider, matching ElasticsearchConfig. Auth is skipped when username is blank (ES security disabled). Co-Authored-By: Claude Opus 4.8 (1M context) * fix: pom version --------- Co-authored-by: Claude Opus 4.8 (1M context) --- pom.xml | 2 +- .../service/health/HealthService.java | 37 ++++++++++++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 0b2dea62..ae4c0f8f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.iemr.common.identity identity-api - 3.8.0 + 3.8.2 war diff --git a/src/main/java/com/iemr/common/identity/service/health/HealthService.java b/src/main/java/com/iemr/common/identity/service/health/HealthService.java index f233d729..a8385b11 100644 --- a/src/main/java/com/iemr/common/identity/service/health/HealthService.java +++ b/src/main/java/com/iemr/common/identity/service/health/HealthService.java @@ -48,10 +48,14 @@ import javax.management.ObjectName; import jakarta.annotation.PostConstruct; import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.elasticsearch.client.Request; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -116,6 +120,8 @@ public class HealthService { private final boolean elasticsearchEnabled; private final boolean elasticsearchIndexingRequired; private final String elasticsearchTargetIndex; + private final String elasticsearchUsername; + private final String elasticsearchPassword; private static final ObjectMapper objectMapper = new ObjectMapper(); private RestClient elasticsearchRestClient; @@ -139,7 +145,9 @@ public HealthService( @Value("${elasticsearch.port:9200}") int elasticsearchPort, @Value("${elasticsearch.enabled:false}") boolean elasticsearchEnabled, @Value("${elasticsearch.target-index:amrit_data}") String elasticsearchTargetIndex, - @Value("${elasticsearch.indexing-required:false}") boolean elasticsearchIndexingRequired) { + @Value("${elasticsearch.indexing-required:false}") boolean elasticsearchIndexingRequired, + @Value("${elasticsearch.username:}") String elasticsearchUsername, + @Value("${elasticsearch.password:}") String elasticsearchPassword) { this.dataSource = dataSource; this.advancedCheckExecutor = Executors.newSingleThreadExecutor(r -> { @@ -153,6 +161,8 @@ public HealthService( this.elasticsearchEnabled = elasticsearchEnabled; this.elasticsearchIndexingRequired = elasticsearchIndexingRequired; this.elasticsearchTargetIndex = (elasticsearchTargetIndex != null) ? elasticsearchTargetIndex : "amrit_data"; + this.elasticsearchUsername = elasticsearchUsername; + this.elasticsearchPassword = elasticsearchPassword; } @PostConstruct @@ -176,15 +186,30 @@ public void cleanup() { private void initializeElasticsearchClient() { try { - this.elasticsearchRestClient = RestClient.builder( + RestClientBuilder builder = RestClient.builder( new HttpHost(elasticsearchHost, elasticsearchPort, "http")) .setRequestConfigCallback(cb -> cb .setConnectTimeout(ELASTICSEARCH_CONNECT_TIMEOUT_MS) - .setSocketTimeout(ELASTICSEARCH_SOCKET_TIMEOUT_MS)) - .build(); + .setSocketTimeout(ELASTICSEARCH_SOCKET_TIMEOUT_MS)); + + // Attach Basic Auth when credentials are configured, so the health + // probes authenticate against a security-enabled cluster (matches + // ElasticsearchConfig). When username is blank (security disabled), + // the client stays unauthenticated. + if (elasticsearchUsername != null && !elasticsearchUsername.isEmpty()) { + BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials( + AuthScope.ANY, + new UsernamePasswordCredentials(elasticsearchUsername, elasticsearchPassword)); + builder.setHttpClientConfigCallback(httpClientBuilder -> + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)); + } + + this.elasticsearchRestClient = builder.build(); this.elasticsearchClientReady = true; - logger.info("Elasticsearch client initialized (connect/socket timeout: {}ms)", - ELASTICSEARCH_CONNECT_TIMEOUT_MS); + logger.info("Elasticsearch client initialized (connect/socket timeout: {}ms, auth: {})", + ELASTICSEARCH_CONNECT_TIMEOUT_MS, + (elasticsearchUsername != null && !elasticsearchUsername.isEmpty()) ? "enabled" : "disabled"); } catch (Exception e) { logger.warn("Failed to initialize Elasticsearch client: {}", e.getMessage()); this.elasticsearchClientReady = false; From 26032ed767270c931f5a428820900700ca8e8299 Mon Sep 17 00:00:00 2001 From: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Date: Tue, 28 Jul 2026 15:32:01 +0530 Subject: [PATCH 38/42] Merge 3.8.2 code (#177) * feat: write anthropometry from rmnch/syncDataToAmrit to i_beneficiarydetails.otherFields Mobile sends height/weight/bmi/temperature in beneficiaryDetails payload. i_beneficiarydetails_rmnch has no these columns so they were lost. FLW-API getBeneficiaryData reads from otherFields (temperatureValue key). - RMNCHBeneficiaryDetailsRmnch: @Transient height/weight/bmi/temperature - BenDetailRepo: updateOtherFieldsByBenRegId query - RmnchDataSyncServiceImpl: merge anthropometry into otherFields after save Co-Authored-By: Claude Sonnet 4.6 * feat: stamp vanID from Redis on all 4 RMNCH entities in syncDataToAmrit Reads camp:vanID and camp:parkingPlaceID from Redis (written by MMU-API on van login) and stamps them onto RMNCHBeneficiaryDetailsRmnch, RMNCHBornBirthDetails, RMNCHCBACdetails, and RMNCHHouseHoldDetails when the mobile payload carries VanID=null or 0. Also writes anthropometry (height/weight/bmi/temperature) from mobile beneficiaryDetails payload into i_beneficiarydetails.otherFields so FLW-API getBeneficiaryData can return them. Gracefully skips if Redis has no camp configured. Co-Authored-By: Claude Sonnet 4.6 * fix: preserve @Transient anthropometry fields lost after JPA saveAll merge Hibernate merge() returns new managed instances that do not carry @Transient field values (height/weight/bmi/temperature). Keep a reference to the original list before saveAll so the anthropometry loop reads from objects that still have the mobile payload values. Co-Authored-By: Claude Sonnet 4.6 * fix: prevent camp:vanID deletion on every syncDataToAmrit call getObject("camp:vanID", false, 0) was calling EXPIRE key 0 which immediately deletes the key in Redis after every sync. Replaced with getRaw() which reads the value without modifying TTL, so camp:vanID persists across multiple syncs until MMU logout. Co-Authored-By: Claude Sonnet 4.6 * feat(stoptb): add stoptb.enforce.vanid flag to syncDataToAmrit The Stop TB mobile app calls this RMNCH sync endpoint directly to save household details. Same issue as elsewhere: vanID stamping is skipped silently when Redis has no camp:vanID, so household records end up with vanID=NULL. When stoptb.enforce.vanid=true, sync now fails with a clear error instead. * feat(STOP-148): add GPS location capture support for beneficiary and RMNCH records Introduces GPS-related fields (gpsLatitude, gpsLongitude, digipin, gpsTimestamp, isGpsUnavailable, and gpsUnavailableReason) across beneficiary address and RMNCH domain models, including MBeneficiaryaddress, Address DTO, RMNCHBeneficiaryDetailsRmnch, and RMNCHHouseHoldDetails. Enhances IdentityMapper and IdentityService to map and persist GPS information between incoming DTOs and beneficiary address entities. Updates RmnchDataSyncServiceImpl to extract and synchronize GPS details from the nested i_bendemographics payload during beneficiary sync, and to parse gpsTimestamp from household details during RMNCH household data processing. * feat(STOP-148): add GPS location capture support for beneficiary and RMNCH records (#167) Introduces GPS-related fields (gpsLatitude, gpsLongitude, digipin, gpsTimestamp, isGpsUnavailable, and gpsUnavailableReason) across beneficiary address and RMNCH domain models, including MBeneficiaryaddress, Address DTO, RMNCHBeneficiaryDetailsRmnch, and RMNCHHouseHoldDetails. Enhances IdentityMapper and IdentityService to map and persist GPS information between incoming DTOs and beneficiary address entities. Updates RmnchDataSyncServiceImpl to extract and synchronize GPS details from the nested i_bendemographics payload during beneficiary sync, and to parse gpsTimestamp from household details during RMNCH household data processing. Co-authored-by: Sehjot Singh Pannu * fix(STOP-148): use InputMapper Gson for createIdentity to parse epoch-millis gpsTimestamp createIdentity() parsed the request body with a bare new Gson(), whose default Timestamp adapter only accepts ISO8601 date strings. The new gpsTimestamp field is sent as raw epoch millis, causing JsonSyntaxException during parsing whenever GPS data is present. That exception propagated up through JwtUserIdValidationFilter's catch block and was misreported as a 401 Authorization error. InputMapper already registers a Timestamp adapter that handles epoch millis correctly; switch createIdentity() to use it. Co-Authored-By: Claude Sonnet 4.6 * fix(datasync): add vanID column to BenGenID import INSERT query SQL had 6 placeholders but object array had 7 elements including vanID, causing parameter index out of bounds error. Added vanID to INSERT columns. Co-Authored-By: Claude Sonnet 4.6 * fix(rmnch): surface pinCode in beneficiary details sync response permPinCode was already stored correctly in i_beneficiaryaddress but was never surfaced in the RMNCH sync response, since the response DTO had no pinCode field and the address mapping never copied it across. Co-Authored-By: Claude Sonnet 5 * fix(dob): stop global Timestamp adapter from nulling dob on GPS-enabled endpoints The GPS feature (STOP-148) registered a custom Gson TypeAdapter globally on InputMapper's GsonBuilder to parse the new gpsTimestamp field. Because it was global, it also intercepted dob, silently returning null whenever the incoming date string didn't match one of its four hardcoded formats. - Add GpsTimestampAdapter, attached only via @JsonAdapter on the gpsTimestamp field (Address, RMNCHBeneficiaryDetailsRmnch, RMNCHHouseHoldDetails), so it can't affect any other Timestamp field. - Remove the global registerTypeAdapter(Timestamp.class, ...) from both InputMapper.java copies, restoring Gson's default Timestamp parsing for dob and everything else (matching vb/stoptb). - Revert createIdentity()'s parser back to a bare new Gson(), matching Common-API's RegisterBenificiaryServiceImpl, which also serializes the outgoing identity payload with a bare new Gson(). InputMapper's setDateFormat is incompatible with that wire format (non-zero-padded day), which is why dob was nulling specifically for beneficiaries born on the 1st-9th of a month once createIdentity switched to InputMapper's Gson. Co-Authored-By: Claude Sonnet 5 --------- Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Sehjot Singh Pannu --- src/main/environment/common_ci.properties | 3 + src/main/environment/common_docker.properties | 3 + .../environment/common_example.properties | 5 + .../controller/IdentityController.java | 5 + .../rmnch/RMNCHBeneficiaryDetailsRmnch.java | 46 +++ .../data/rmnch/RMNCHHouseHoldDetails.java | 72 +++-- .../iemr/common/identity/domain/Address.java | 12 + .../identity/domain/MBeneficiaryaddress.java | 60 ++-- .../identity/mapper/GpsTimestampAdapter.java | 116 ++++++++ .../identity/mapper/IdentityMapper.java | 84 +++--- .../common/identity/mapper/InputMapper.java | 4 + .../common/identity/repo/BenDetailRepo.java | 5 + .../identity/service/IdentityService.java | 264 +++++++++--------- .../rmnch/RmnchDataSyncServiceImpl.java | 141 +++++++++- .../identity/utils/mapper/InputMapper.java | 5 + .../identity/utils/redis/RedisStorage.java | 7 + 16 files changed, 618 insertions(+), 214 deletions(-) create mode 100644 src/main/java/com/iemr/common/identity/mapper/GpsTimestampAdapter.java diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index e32dc366..1ce43664 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -22,6 +22,9 @@ fhir-url=@env.FHIR_API@ # Redis Config spring.redis.host=@env.REDIS_HOST@ +# Stop TB: when true, RMNCH data sync fails with an error if camp (vanID) is not configured +stoptb.enforce.vanid=@env.STOPTB_ENFORCE_VANID@ + cors.allowed-origins=@env.CORS_ALLOWED_ORIGINS@ # Elasticsearch Configuration diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index 07bd53cc..36735700 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -22,6 +22,9 @@ fhir-url=${FHIR_API} # Redis Config spring.redis.host=${REDIS_HOST} +# Stop TB: when true, RMNCH data sync fails with an error if camp (vanID) is not configured +stoptb.enforce.vanid=${STOPTB_ENFORCE_VANID} + cors.allowed-origins=${CORS_ALLOWED_ORIGINS} # Elasticsearch Configuration diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index b78483f2..dd235c95 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -17,6 +17,11 @@ fhir-url=http://localhost:8093/ # Redis Config spring.redis.host=localhost + +# Stop TB: when true, RMNCH data sync fails with an error if camp (vanID) is not +# configured instead of silently skipping vanID stamping +stoptb.enforce.vanid=false + cors.allowed-origins=http://localhost:* # Elasticsearch Configuration diff --git a/src/main/java/com/iemr/common/identity/controller/IdentityController.java b/src/main/java/com/iemr/common/identity/controller/IdentityController.java index fc894761..8d015bd1 100644 --- a/src/main/java/com/iemr/common/identity/controller/IdentityController.java +++ b/src/main/java/com/iemr/common/identity/controller/IdentityController.java @@ -608,6 +608,11 @@ public String createIdentity(@Param(value = "{\r\n" + " \"eventTypeName\": \"St + " \"createdDate\": \"Timestamp\"\r\n" + " \"faceEmbedding\": [\"Float\"]\r\n" + "}") @RequestBody String identityData) throws IEMRException { logger.info("IdentityController.createIdentity - start"); + // Bare Gson matches Common-API's RegisterBenificiaryServiceImpl, which also + // serializes the outgoing identity payload with a bare new Gson(). dob relies + // on this symmetric default format; gpsTimestamp is still parsed correctly via + // its field-level @JsonAdapter(GpsTimestampAdapter.class) on Address, which + // works regardless of which Gson instance performs the parse. IdentityDTO identity = new Gson().fromJson(identityData, IdentityDTO.class); logger.info("identity hit: " + identity); BeneficiaryCreateResp map; diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java index 1fb1b66d..814d2c73 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java @@ -34,6 +34,8 @@ import jakarta.persistence.Transient; import com.google.gson.annotations.Expose; +import com.google.gson.annotations.JsonAdapter; +import com.iemr.common.identity.mapper.GpsTimestampAdapter; import lombok.Data; @@ -390,6 +392,9 @@ public class RMNCHBeneficiaryDetailsRmnch { @Expose @Transient private String addressLine3; + @Expose + @Transient + private String pinCode; // ---------------------------------------------- @@ -557,4 +562,45 @@ public class RMNCHBeneficiaryDetailsRmnch { @Expose @Transient private String familyId; + + // Anthropometry fields sent by Stop TB mobile app via beneficiaryDetails payload. + // i_beneficiarydetails_rmnch has no these columns — stored in i_beneficiarydetails.otherFields instead. + @Expose + @Transient + private Double height; + @Expose + @Transient + private Double weight; + @Expose + @Transient + private Double bmi; + @Expose + @Transient + private Double temperature; // stored as "temperatureValue" in otherFields to match getBeneficiaryData key + + @Expose + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Expose + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Expose + @Column(name = "digipin") + private String digipin; + + @Expose + @Column(name = "gpsTimestamp") + @JsonAdapter(GpsTimestampAdapter.class) + private Timestamp gpsTimestamp; + + @Expose + @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") + private Boolean isGpsUnavailable = false; + + @Expose + @Column(name = "gpsUnavailableReason") + private String gpsUnavailableReason; + } diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java index 8aa8ed47..7000f6d0 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java @@ -1,24 +1,24 @@ /* -* 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 + * 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.common.identity.data.rmnch; import java.sql.Timestamp; @@ -31,11 +31,14 @@ import jakarta.persistence.Table; import com.google.gson.annotations.Expose; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.iemr.common.identity.mapper.GpsTimestampAdapter; import lombok.Data; /** - * + * * @author de40034072 * */ @@ -359,4 +362,31 @@ public class RMNCHHouseHoldDetails { @Column(name = "mohallaName") private String mohallaName; + @Expose + @SerializedName("latitude") + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Expose + @SerializedName("longitude") + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Expose + @Column(name = "digipin") + private String digipin; + + @Expose + @Column(name = "gpsTimestamp") + @JsonAdapter(GpsTimestampAdapter.class) + private Timestamp gpsTimestamp; + + @Expose + @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") + private Boolean isGpsUnavailable = false; + + @Expose + @Column(name = "gpsUnavailableReason") + private String gpsUnavailableReason; + } diff --git a/src/main/java/com/iemr/common/identity/domain/Address.java b/src/main/java/com/iemr/common/identity/domain/Address.java index c37b4507..f355cbc8 100644 --- a/src/main/java/com/iemr/common/identity/domain/Address.java +++ b/src/main/java/com/iemr/common/identity/domain/Address.java @@ -23,6 +23,11 @@ import lombok.Data; +import java.sql.Timestamp; + +import com.google.gson.annotations.JsonAdapter; +import com.iemr.common.identity.mapper.GpsTimestampAdapter; + public @Data class Address { private String addrLine1; private String addrLine2; @@ -51,4 +56,11 @@ private Integer vanID; private Integer parkingPlaceID; + private Double gpsLatitude; + private Double gpsLongitude; + private String digipin; + @JsonAdapter(GpsTimestampAdapter.class) + private Timestamp gpsTimestamp; + private Boolean isGpsUnavailable; + private String gpsUnavailableReason; } diff --git a/src/main/java/com/iemr/common/identity/domain/MBeneficiaryaddress.java b/src/main/java/com/iemr/common/identity/domain/MBeneficiaryaddress.java index 0e2ab415..d5eaf7bd 100644 --- a/src/main/java/com/iemr/common/identity/domain/MBeneficiaryaddress.java +++ b/src/main/java/com/iemr/common/identity/domain/MBeneficiaryaddress.java @@ -1,24 +1,24 @@ /* -* 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 + * 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.common.identity.domain; import java.io.Serializable; @@ -39,7 +39,7 @@ /** * The persistent class for the m_beneficiaryaddress database table. - * + * */ @Entity @Table(name = "i_beneficiaryaddress") @@ -260,6 +260,24 @@ public class MBeneficiaryaddress implements Serializable { // END OF new column added for data sync + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Column(name = "digipin") + private String digipin; + + @Column(name = "gpsTimestamp") + private Timestamp gpsTimestamp; + + @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") + private Boolean isGpsUnavailable = false; + + @Column(name = "gpsUnavailableReason") + private String gpsUnavailableReason; + public MBeneficiaryaddress setCurrentAddress(Address address) { this.currAddrLine1 = address.getAddrLine1(); this.currAddrLine2 = address.getAddrLine2(); diff --git a/src/main/java/com/iemr/common/identity/mapper/GpsTimestampAdapter.java b/src/main/java/com/iemr/common/identity/mapper/GpsTimestampAdapter.java new file mode 100644 index 00000000..1f1fe2ff --- /dev/null +++ b/src/main/java/com/iemr/common/identity/mapper/GpsTimestampAdapter.java @@ -0,0 +1,116 @@ +/* +* 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.common.identity.mapper; + +import java.io.IOException; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +/** + * Parses the GPS capture timestamp (epoch millis, ISO-8601 with/without a literal + * 'Z', or the mobile client's "MMM dd, yyyy, h:mm:ss a" format). + * + * Attach with {@code @JsonAdapter(GpsTimestampAdapter.class)} directly on a + * gpsTimestamp field only. Do NOT register this globally on a GsonBuilder for + * Timestamp.class — that previously intercepted every Timestamp field in the + * request (including dob) and silently nulled it out whenever the client's + * format didn't match one of the patterns below. + */ +public class GpsTimestampAdapter extends TypeAdapter { + + private static final Logger logger = LoggerFactory.getLogger(GpsTimestampAdapter.class); + + private static final DateTimeFormatter ISO_WITH_Z = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + private static final DateTimeFormatter ISO_NO_TZ = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"); + private static final DateTimeFormatter CLIENT_DATE_FORMAT = + DateTimeFormatter.ofPattern("MMM dd, yyyy, h:mm:ss a", Locale.ENGLISH); + + @Override + public void write(JsonWriter out, Timestamp value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.getTime()); + } + } + + @Override + public Timestamp read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + if (in.peek() == JsonToken.NUMBER) { + return new Timestamp(in.nextLong()); + } + + String s = in.nextString(); + + // epoch millis as string + try { + return new Timestamp(Long.parseLong(s)); + } catch (NumberFormatException ignored) { + // not epoch millis, try the date formats below + } + // ISO 8601 with Z, e.g. "2021-06-18T00:00:00.000Z" + try { + return Timestamp.from(Instant.parse(s)); + } catch (Exception ignored) { + // not this format + } + // Mobile client format, e.g. "Jun 18, 2021, 5:30:00 AM" + try { + return Timestamp.valueOf(LocalDateTime.parse(s, CLIENT_DATE_FORMAT)); + } catch (Exception ignored) { + // not this format + } + // ISO with literal 'Z' pattern, e.g. "2021-06-18T00:00:00.000Z" parsed as local + try { + return Timestamp.valueOf(LocalDateTime.parse(s, ISO_WITH_Z)); + } catch (Exception ignored) { + // not this format + } + // ISO without timezone, e.g. "2021-06-18T00:00:00.000" (assume UTC) + try { + return Timestamp.from(LocalDateTime.parse(s, ISO_NO_TZ).toInstant(ZoneOffset.UTC)); + } catch (Exception ignored) { + // not this format + } + + logger.warn("GpsTimestampAdapter: unable to parse gpsTimestamp value '{}' with any known format; storing as null", s); + return null; + } +} diff --git a/src/main/java/com/iemr/common/identity/mapper/IdentityMapper.java b/src/main/java/com/iemr/common/identity/mapper/IdentityMapper.java index bc3ad686..765acb97 100644 --- a/src/main/java/com/iemr/common/identity/mapper/IdentityMapper.java +++ b/src/main/java/com/iemr/common/identity/mapper/IdentityMapper.java @@ -1,24 +1,24 @@ /* -* 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 + * 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.common.identity.mapper; import java.sql.Timestamp; @@ -66,7 +66,7 @@ public interface IdentityMapper { MBeneficiarymapping identityDTOToMBeneficiarymapping(IdentityDTO dto); - + @Mapping(source = "defaultNo", target = "shareAnonymousWithGovt") @Mapping(source = "defaultNo", target = "shareAnonymousWithMedicalCommunity") @@ -93,7 +93,7 @@ public interface IdentityMapper { MBeneficiaryconsent identityDTOToDefaultMBeneficiaryconsent(IdentityDTO dto, Boolean defaultYes, Boolean defaultNo); - + // @Mapping(source = "dto.areaId", target = "areaId") // @Mapping(source = "dto.beneficiaryRegId", target = "beneficiaryRegID") @@ -144,7 +144,7 @@ public interface IdentityMapper { // @Mapping(source = "dto.vanID", target = "vanID") // @Mapping(source = "dto.parkingPlaceId", target = "parkingPlaceID") // MBeneficiarydetail identityDTOToMBeneficiarydetail(IdentityDTO dto); - + @Mapping(source = "benFamilyDTO.isEmergencyContact", target = "isEmergencyContact") @Mapping(source = "benFamilyDTO.relationshipToSelf", target = "relationshipToSelf") @@ -152,7 +152,7 @@ public interface IdentityMapper { @Mapping(source = "createdBy", target = "createdBy") @Mapping(source = "createdDate", target = "createdDate") MBeneficiaryfamilymapping identityDTOToMBeneficiaryfamilymapping(BenFamilyDTO benFamilyDTO, String createdBy, - Timestamp createdDate); + Timestamp createdDate); List identityDTOListToMBeneficiaryfamilymappingList(List list); @@ -210,6 +210,12 @@ MBeneficiaryfamilymapping identityDTOToMBeneficiaryfamilymapping(BenFamilyDTO be @Mapping(target = "currentAddress.village", source = "map.MBeneficiaryaddress.currVillage") @Mapping(target = "currentAddress.addressValue", source = "map.MBeneficiaryaddress.currAddressValue") @Mapping(target = "currentAddress.pinCode", source = "map.MBeneficiaryaddress.currPinCode") + @Mapping(target = "currentAddress.gpsLatitude", source = "map.MBeneficiaryaddress.gpsLatitude") + @Mapping(target = "currentAddress.gpsLongitude", source = "map.MBeneficiaryaddress.gpsLongitude") + @Mapping(target = "currentAddress.digipin", source = "map.MBeneficiaryaddress.digipin") + @Mapping(target = "currentAddress.gpsTimestamp", source = "map.MBeneficiaryaddress.gpsTimestamp") + @Mapping(target = "currentAddress.isGpsUnavailable", source = "map.MBeneficiaryaddress.isGpsUnavailable") + @Mapping(target = "currentAddress.gpsUnavailableReason", source = "map.MBeneficiaryaddress.gpsUnavailableReason") @Mapping(target = "emergencyAddress.addrLine1", source = "map.MBeneficiaryaddress.emerAddrLine1") @Mapping(target = "emergencyAddress.addrLine2", source = "map.MBeneficiaryaddress.emerAddrLine2") @Mapping(target = "emergencyAddress.addrLine3", source = "map.MBeneficiaryaddress.emerAddrLine3") @@ -296,13 +302,13 @@ MBeneficiaryfamilymapping identityDTOToMBeneficiaryfamilymapping(BenFamilyDTO be @Mapping(target = "beneficiaryDetails.title", source = "map.MBeneficiarydetail.title") @Mapping(target = "beneficiaryDetails.zoneId", source = "map.MBeneficiarydetail.zoneId") @Mapping(target = "contacts", expression = "java( map != null && map.getMBeneficiarycontact() != null && " - + "map.getMBeneficiarydetail() != null ? " - + "Phone.createContactList(map.getMBeneficiarycontact(), " - + "(benRegId != null ? benRegId.toString() : null), " - + "(map.getMBeneficiarydetail().getFirstName() != null ? map.getMBeneficiarydetail().getFirstName() : \"\") + \" \" + " - + "(map.getMBeneficiarydetail().getMiddleName() != null ? map.getMBeneficiarydetail().getMiddleName() : \"\") + \" \" + " - + "(map.getMBeneficiarydetail().getLastName() != null ? map.getMBeneficiarydetail().getLastName() : \"\") " - + ") : null)") + + "map.getMBeneficiarydetail() != null ? " + + "Phone.createContactList(map.getMBeneficiarycontact(), " + + "(map.getBenRegId() != null ? map.getBenRegId().toString() : null), " + + "(map.getMBeneficiarydetail().getFirstName() != null ? map.getMBeneficiarydetail().getFirstName() : \"\") + \" \" + " + + "(map.getMBeneficiarydetail().getMiddleName() != null ? map.getMBeneficiarydetail().getMiddleName() : \"\") + \" \" + " + + "(map.getMBeneficiarydetail().getLastName() != null ? map.getMBeneficiarydetail().getLastName() : \"\") " + + ") : null)") @Mapping(target = "permanentAddress.zoneID", source = "map.MBeneficiaryaddress.permZoneID") @Mapping(target = "permanentAddress.zoneName", source = "map.MBeneficiaryaddress.permZone") @@ -334,13 +340,13 @@ MBeneficiaryfamilymapping identityDTOToMBeneficiaryfamilymapping(BenFamilyDTO be @Mapping(target = "accountNo", source = "map.MBeneficiaryAccount.accountNo") @Mapping(target = "benAccountID", source = "map.benAccountID") @Mapping(target = "ageAtMarriage", expression = "java(map != null && map.getMBeneficiarydetail() != null ? " - + "MBeneficiarydetail.getAgeAtMarriageCalc(map.getMBeneficiarydetail().getDob(), " - + "map.getMBeneficiarydetail().getMarriageDate(), " - + "map.getMBeneficiarydetail().getAgeAtMarriage()) : null)") + + "MBeneficiarydetail.getAgeAtMarriageCalc(map.getMBeneficiarydetail().getDob(), " + + "map.getMBeneficiarydetail().getMarriageDate(), " + + "map.getMBeneficiarydetail().getAgeAtMarriage()) : null)") @Mapping(target = "marriageDate", expression = "java(map != null && map.getMBeneficiarydetail() != null ? " - + "MBeneficiarydetail.getMarriageDateCalc(map.getMBeneficiarydetail().getDob(), " - + "map.getMBeneficiarydetail().getMarriageDate(), " - + "map.getMBeneficiarydetail().getAgeAtMarriage()) : null)") + + "MBeneficiarydetail.getMarriageDateCalc(map.getMBeneficiarydetail().getDob(), " + + "map.getMBeneficiarydetail().getMarriageDate(), " + + "map.getMBeneficiarydetail().getAgeAtMarriage()) : null)") @Mapping(target = "literacyStatus", source = "map.MBeneficiarydetail.literacyStatus") @Mapping(target = "motherName", source = "map.MBeneficiarydetail.motherName") @@ -481,7 +487,7 @@ List mapToMBeneficiaryfamilymappingWithBenFamilyDTOList( @Mapping(source = "dto.createdDate", target = "createdDate") @Mapping(source = "dto.vanID", target = "vanID") @Mapping(source = "dto.parkingPlaceId", target = "parkingPlaceID") - // End + // End MBeneficiaryAccount identityDTOToMBeneficiaryAccount(IdentityDTO dto); @InheritInverseConfiguration @@ -490,7 +496,7 @@ List mapToMBeneficiaryfamilymappingWithBenFamilyDTOList( @Mapping(source = "dto.benImage", target = "benImage") @Mapping(source = "dto.agentName", target = "createdBy") @Mapping(source = "dto.createdDate", target = "createdDate") - + @Mapping(source = "dto.vanID", target = "vanID") @Mapping(source = "dto.parkingPlaceId", target = "parkingPlaceID") diff --git a/src/main/java/com/iemr/common/identity/mapper/InputMapper.java b/src/main/java/com/iemr/common/identity/mapper/InputMapper.java index 9a46ba4f..3549efc2 100644 --- a/src/main/java/com/iemr/common/identity/mapper/InputMapper.java +++ b/src/main/java/com/iemr/common/identity/mapper/InputMapper.java @@ -44,6 +44,10 @@ public class InputMapper private InputMapper() { + // Timestamp fields (including dob) use Gson's default parsing here, same as + // on vb/stoptb. The gpsTimestamp field on Address/RMNCH entities is parsed by + // GpsTimestampAdapter via a field-level @JsonAdapter annotation instead of a + // global registration, so it can't affect any other Timestamp field. builder = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") // .excludeFieldsWithoutExposeAnnotation() .serializeNulls().setLongSerializationPolicy(LongSerializationPolicy.STRING); diff --git a/src/main/java/com/iemr/common/identity/repo/BenDetailRepo.java b/src/main/java/com/iemr/common/identity/repo/BenDetailRepo.java index 4e8bcc01..413298ba 100644 --- a/src/main/java/com/iemr/common/identity/repo/BenDetailRepo.java +++ b/src/main/java/com/iemr/common/identity/repo/BenDetailRepo.java @@ -148,6 +148,11 @@ int untagFamily(@Param("modifiedBy") String modifiedBy, @Param("vanSerialNo") Bi @Query("SELECT b FROM MBeneficiarydetail b WHERE b.familyId =:familyid ") List searchByFamilyId(@Param("familyid") String familyid); + @Transactional + @Modifying + @Query("UPDATE MBeneficiarydetail d SET d.otherFields = :otherFields WHERE d.mBeneficiarymapping.benRegId = :benRegId") + int updateOtherFieldsByBenRegId(@Param("benRegId") BigInteger benRegId, @Param("otherFields") String otherFields); + /** * Find complete beneficiary data by IDs from Elasticsearch */ diff --git a/src/main/java/com/iemr/common/identity/service/IdentityService.java b/src/main/java/com/iemr/common/identity/service/IdentityService.java index 90e660b9..bb1dd988 100644 --- a/src/main/java/com/iemr/common/identity/service/IdentityService.java +++ b/src/main/java/com/iemr/common/identity/service/IdentityService.java @@ -1,23 +1,23 @@ /* -* 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 + * 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.common.identity.service; @@ -229,7 +229,7 @@ public List getBeneficiaries(IdentitySearchDTO searchDTO) if (list3.get(i) == null || list3.get(i).getBeneficiaryDetails() == null || list3.get(i).getBeneficiaryDetails().getFirstName() == null || !list3.get(i).getBeneficiaryDetails().getFirstName() - .equalsIgnoreCase(searchDTO.getFirstName())) { + .equalsIgnoreCase(searchDTO.getFirstName())) { list3.remove(i); i--; @@ -241,7 +241,7 @@ public List getBeneficiaries(IdentitySearchDTO searchDTO) if (list3.get(i) == null || list3.get(i).getBeneficiaryDetails() == null || list3.get(i).getBeneficiaryDetails().getLastName() == null || !list3.get(i).getBeneficiaryDetails().getLastName() - .equalsIgnoreCase(searchDTO.getLastName())) { + .equalsIgnoreCase(searchDTO.getLastName())) { list3.remove(i); i--; @@ -286,7 +286,7 @@ public List getBeneficiaries(IdentitySearchDTO searchDTO) if (list3.get(i) == null || list3.get(i).getCurrentAddress() == null || list3.get(i).getCurrentAddress().getDistrictId() == null || !list3.get(i).getCurrentAddress().getDistrictId() - .equals(searchDTO.getCurrentAddress().getDistrictId())) { + .equals(searchDTO.getCurrentAddress().getDistrictId())) { list3.remove(i); i--; @@ -298,7 +298,7 @@ public List getBeneficiaries(IdentitySearchDTO searchDTO) if (list3.get(i) == null || list3.get(i).getCurrentAddress() == null || list3.get(i).getCurrentAddress().getVillageId() == null || !list3.get(i).getCurrentAddress().getVillageId() - .equals(searchDTO.getCurrentAddress().getVillageId())) { + .equals(searchDTO.getCurrentAddress().getVillageId())) { list3.remove(i); i--; @@ -515,7 +515,7 @@ public List getBeneficiariesByBenId(BigInteger benId) /** * - * @param BenRegId + * @param benRegId * @return */ public List getBeneficiariesByBenRegId(BigInteger benRegId) @@ -591,104 +591,104 @@ public List getBeneficiariesByPhoneNum(String phoneNum) } -/** - * Advanced search using Elasticsearch with fallback to database - */ -public Map advancedSearchBeneficiariesES( - String firstName, String middleName, String lastName, Integer genderId, java.util.Date dob, - Integer stateId, Integer districtId, Integer blockId, Integer villageId, - String fatherName, String spouseName, String maritalStatus, String phoneNumber, - String beneficiaryId, String healthId, String aadharNo, - Integer userId, String auth, Boolean is1097) throws Exception { - - try { - logger.info("IdentityService.advancedSearchBeneficiariesES - start"); - logger.info("ES enabled: {}", esEnabled); - - Map response = new HashMap<>(); - - if (esEnabled) { - logger.info("Using Elasticsearch for advanced search"); - - // Call Elasticsearch service - List> esResults = elasticsearchService.advancedSearch( - firstName, middleName, lastName, genderId, dob, stateId, districtId, - blockId, villageId, fatherName, spouseName, maritalStatus, phoneNumber, - beneficiaryId, healthId, aadharNo, userId - ); - - response.put("data", esResults); - response.put("count", esResults.size()); - response.put("source", "elasticsearch"); - - logger.info("ES returned {} results", esResults.size()); - - } else { - logger.info("ES disabled - using database for advanced search"); - - IdentitySearchDTO searchDTO = new IdentitySearchDTO(); - searchDTO.setFirstName(firstName); - searchDTO.setLastName(lastName); - searchDTO.setGenderId(genderId); - searchDTO.setDob(dob != null ? new Timestamp(dob.getTime()) : null); - searchDTO.setFatherName(fatherName); - searchDTO.setSpouseName(spouseName); - searchDTO.setContactNumber(phoneNumber); - - if (beneficiaryId != null && !beneficiaryId.trim().isEmpty()) { - try { - searchDTO.setBeneficiaryId(new BigInteger(beneficiaryId)); - } catch (NumberFormatException e) { - logger.warn("Invalid beneficiaryId format: {}", beneficiaryId); + /** + * Advanced search using Elasticsearch with fallback to database + */ + public Map advancedSearchBeneficiariesES( + String firstName, String middleName, String lastName, Integer genderId, Date dob, + Integer stateId, Integer districtId, Integer blockId, Integer villageId, + String fatherName, String spouseName, String maritalStatus, String phoneNumber, + String beneficiaryId, String healthId, String aadharNo, + Integer userId, String auth, Boolean is1097) throws Exception { + + try { + logger.info("IdentityService.advancedSearchBeneficiariesES - start"); + logger.info("ES enabled: {}", esEnabled); + + Map response = new HashMap<>(); + + if (esEnabled) { + logger.info("Using Elasticsearch for advanced search"); + + // Call Elasticsearch service + List> esResults = elasticsearchService.advancedSearch( + firstName, middleName, lastName, genderId, dob, stateId, districtId, + blockId, villageId, fatherName, spouseName, maritalStatus, phoneNumber, + beneficiaryId, healthId, aadharNo, userId + ); + + response.put("data", esResults); + response.put("count", esResults.size()); + response.put("source", "elasticsearch"); + + logger.info("ES returned {} results", esResults.size()); + + } else { + logger.info("ES disabled - using database for advanced search"); + + IdentitySearchDTO searchDTO = new IdentitySearchDTO(); + searchDTO.setFirstName(firstName); + searchDTO.setLastName(lastName); + searchDTO.setGenderId(genderId); + searchDTO.setDob(dob != null ? new Timestamp(dob.getTime()) : null); + searchDTO.setFatherName(fatherName); + searchDTO.setSpouseName(spouseName); + searchDTO.setContactNumber(phoneNumber); + + if (beneficiaryId != null && !beneficiaryId.trim().isEmpty()) { + try { + searchDTO.setBeneficiaryId(new BigInteger(beneficiaryId)); + } catch (NumberFormatException e) { + logger.warn("Invalid beneficiaryId format: {}", beneficiaryId); + } } + + if (stateId != null || districtId != null || blockId != null || villageId != null) { + Address addressDTO = new Address(); + addressDTO.setStateId(stateId); + addressDTO.setDistrictId(districtId); + addressDTO.setSubDistrictId(blockId); + addressDTO.setVillageId(villageId); + searchDTO.setCurrentAddress(addressDTO); + } + + List dbResults = this.getBeneficiaries(searchDTO); + + List> formattedResults = dbResults.stream() + .map(this::convertBeneficiaryDTOToMap) + .collect(Collectors.toList()); + + response.put("data", formattedResults); + response.put("count", formattedResults.size()); + response.put("source", "database"); + + logger.info("Database returned {} results", formattedResults.size()); } - - if (stateId != null || districtId != null || blockId != null || villageId != null) { - Address addressDTO = new Address(); - addressDTO.setStateId(stateId); - addressDTO.setDistrictId(districtId); - addressDTO.setSubDistrictId(blockId); - addressDTO.setVillageId(villageId); - searchDTO.setCurrentAddress(addressDTO); - } - - List dbResults = this.getBeneficiaries(searchDTO); - - List> formattedResults = dbResults.stream() - .map(this::convertBeneficiaryDTOToMap) - .collect(Collectors.toList()); - - response.put("data", formattedResults); - response.put("count", formattedResults.size()); - response.put("source", "database"); - - logger.info("Database returned {} results", formattedResults.size()); - } - - logger.info("IdentityService.advancedSearchBeneficiariesES - end"); - return response; - - } catch (Exception e) { - logger.error("Advanced search failed: {}", e.getMessage(), e); - throw new Exception("Error in advanced search: " + e.getMessage(), e); - } -}/** - * Convert BeneficiariesDTO to Map format - */ -private Map convertBeneficiaryDTOToMap(BeneficiariesDTO dto) { - try { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(dto); - return mapper.readValue(json, Map.class); - } catch (Exception e) { - logger.error("Error converting DTO to map", e); - return new HashMap<>(); + + logger.info("IdentityService.advancedSearchBeneficiariesES - end"); + return response; + + } catch (Exception e) { + logger.error("Advanced search failed: {}", e.getMessage(), e); + throw new Exception("Error in advanced search: " + e.getMessage(), e); + } + }/** + * Convert BeneficiariesDTO to Map format + */ + private Map convertBeneficiaryDTOToMap(BeneficiariesDTO dto) { + try { + ObjectMapper mapper = new ObjectMapper(); + String json = mapper.writeValueAsString(dto); + return mapper.readValue(json, Map.class); + } catch (Exception e) { + logger.error("Error converting DTO to map", e); + return new HashMap<>(); + } } -} - /** + /** * * * * Search beneficiary by healthID / ABHA address @@ -763,7 +763,7 @@ public List searhBeneficiaryByFamilyId(String familyId) List benDetailsList = detailRepo.searchByFamilyId(familyId); if (benDetailsList == null || benDetailsList.isEmpty()) { - return beneficiaryList; + return beneficiaryList; }else { // considering as of now family creation is possible through facility modules // only @@ -789,7 +789,7 @@ public List searhBeneficiaryByFamilyId(String familyId) } public List searchBeneficiaryByVillageIdAndLastModifyDate(List villageIDs, - Timestamp lastModifiedDate) { + Timestamp lastModifiedDate) { List beneficiaryList = new ArrayList<>(); try { @@ -843,7 +843,7 @@ public List searhBeneficiaryByGovIdentity(String identity) // find benmap ids if (benIdentityList == null || benIdentityList.isEmpty()) { - return beneficiaryList; + return beneficiaryList; }else { for (MBeneficiaryidentity identityObj : benIdentityList) { benMapObjArr.addAll( @@ -1124,7 +1124,7 @@ public void editIdentity(IdentityEditDTO identity) throws MissingMandatoryFields benMapping.getMBeneficiaryaddress().getBenAddressID(), benMapping.getVanID()); // next statement is new one, setting correct beneficiaryDetailsId if (benAddressID != null) { - mbAddr.setBenAddressID(benAddressID); + mbAddr.setBenAddressID(benAddressID); }else { throw new MissingMandatoryFieldsException("Either of vanSerialNO or vanID is missing."); } @@ -1151,7 +1151,7 @@ public void editIdentity(IdentityEditDTO identity) throws MissingMandatoryFields benMapping.getMBeneficiarycontact().getBenContactsID(), benMapping.getVanID()); // next statement is new one, setting correct beneficiaryDetailsId if (benContactsID != null) { - benCon.setBenContactsID(benContactsID); + benCon.setBenContactsID(benContactsID); }else { throw new MissingMandatoryFieldsException("Either of vanSerialNO or vanID is missing."); } @@ -1269,7 +1269,7 @@ public void editIdentity(IdentityEditDTO identity) throws MissingMandatoryFields benMapping.getMBeneficiaryAccount().getBenAccountID(), benMapping.getVanID()); // next statement is new one, setting correct beneficiaryDetailsId if (benAccountID != null) { - beneficiaryAccount.setBenAccountID(benAccountID); + beneficiaryAccount.setBenAccountID(benAccountID); }else { throw new MissingMandatoryFieldsException("Either of vanSerialNO or vanID is missing."); } @@ -1294,7 +1294,7 @@ public void editIdentity(IdentityEditDTO identity) throws MissingMandatoryFields benMapping.getMBeneficiaryImage().getBenImageId(), benMapping.getVanID()); // next statement is new one, setting correct beneficiaryDetailsId if (benImageId != null) { - beneficiaryImage.setBenImageId(benImageId); + beneficiaryImage.setBenImageId(benImageId); }else { throw new MissingMandatoryFieldsException("Either of vanSerialNO or vanID is missing."); } @@ -1314,11 +1314,11 @@ public void editIdentity(IdentityEditDTO identity) throws MissingMandatoryFields logger.info("Triggering Elasticsearch sync for benRegId: {}", identity.getBeneficiaryRegId()); syncService.syncBeneficiaryAsync(identity.getBeneficiaryRegId()); } - - logger.info("IdentityService.editIdentity - end. id = " + benMapping.getBenMapId()); -} - + logger.info("IdentityService.editIdentity - end. id = " + benMapping.getBenMapId()); + } + + private MBeneficiarydetail convertIdentityEditDTOToMBeneficiarydetail(IdentityEditDTO dto) { MBeneficiarydetail beneficiarydetail = new MBeneficiarydetail(); @@ -1829,6 +1829,12 @@ private MBeneficiaryaddress identityDTOToMBeneficiaryaddress(IdentityDTO dto) { beneficiaryAddress.setCurrServicePointId(dto.getCurrentAddress().getServicePointID()); beneficiaryAddress.setCurrServicePoint(dto.getCurrentAddress().getServicePointName()); beneficiaryAddress.setCurrHabitation(dto.getCurrentAddress().getHabitation()); + beneficiaryAddress.setGpsLatitude(dto.getCurrentAddress().getGpsLatitude()); + beneficiaryAddress.setGpsLongitude(dto.getCurrentAddress().getGpsLongitude()); + beneficiaryAddress.setDigipin(dto.getCurrentAddress().getDigipin()); + beneficiaryAddress.setGpsTimestamp(dto.getCurrentAddress().getGpsTimestamp()); + beneficiaryAddress.setIsGpsUnavailable(dto.getCurrentAddress().getIsGpsUnavailable()); + beneficiaryAddress.setGpsUnavailableReason(dto.getCurrentAddress().getGpsUnavailableReason()); } if (dto.getEmergencyAddress() != null) { beneficiaryAddress.setEmerAddrLine1(dto.getEmergencyAddress().getAddrLine1()); @@ -1939,7 +1945,7 @@ public String unReserveIdentity(ReserveIdentityDTO unReserve) { * Get partial details of beneficiaries (first name middle name and last * name) list on benId's list * - * @param BenRegIds + * @param benRegIds * @return {@link List} Beneficiaries */ public List getBeneficiariesPartialDeatilsByBenRegIdList(List benRegIds) { @@ -2157,7 +2163,7 @@ public int importBenIdToLocalServer(List benIdImportDTOList) { List dataList = new ArrayList<>(); Object[] objArr; String query = " INSERT INTO m_beneficiaryregidmapping(BenRegId, BeneficiaryID, " - + " Provisioned, CreatedDate, CreatedBy, Reserved) VALUES (?,?,?,?,?,?) "; + + " Provisioned, CreatedDate, CreatedBy, Reserved, vanID) VALUES (?,?,?,?,?,?,?) "; logger.info("query : " + query); for (MBeneficiaryregidmapping obj : mBeneficiaryregidmappingList) { logger.info("inside for check->", obj); diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 3bbd6b09..528310d4 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -46,6 +46,7 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.google.gson.Gson; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -73,6 +74,9 @@ import com.iemr.common.identity.repo.rmnch.RMNCHCBACDetailsRepo; import com.iemr.common.identity.repo.rmnch.RMNCHHouseHoldDetailsRepo; import com.iemr.common.identity.repo.rmnch.RMNCHMBenMappingRepo; +import com.iemr.common.identity.domain.MBeneficiarydetail; +import com.iemr.common.identity.repo.BenDetailRepo; +import com.iemr.common.identity.utils.redis.RedisStorage; import com.iemr.common.identity.repo.rmnch.RMNCHMBenRegIdMapRepo; import com.iemr.common.identity.utils.config.ConfigProperties; import com.iemr.common.identity.utils.exception.IEMRException; @@ -116,6 +120,16 @@ public class RmnchDataSyncServiceImpl implements RmnchDataSyncService { @Value("${fhir-url}") private String fhirUrl; + + @Autowired + private BenDetailRepo benDetailRepo; + @Autowired + private RedisStorage redisStorage; + + // When true, sync fails loudly if camp is not configured instead of silently + // skipping vanID stamping + @Value("${stoptb.enforce.vanid:false}") + private boolean enforceVanID; @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) @Override public String syncDataToAmrit(String requestOBJ, String authorization) throws Exception { @@ -128,6 +142,24 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex ArrayList cBACDetailsIds = new ArrayList<>(); ArrayList houseHoldDetailsIds = new ArrayList<>(); + // Read camp vanID/parkingPlaceID from Redis (set by MMU-API on van login) + Integer campVanID = null; + Integer campParkingPlaceID = null; + try { + String vanVal = redisStorage.getRaw("camp:vanID"); + String ppVal = redisStorage.getRaw("camp:parkingPlaceID"); + if (vanVal != null && !vanVal.isBlank()) campVanID = Integer.parseInt(vanVal); + if (ppVal != null && !ppVal.isBlank()) campParkingPlaceID = Integer.parseInt(ppVal); + } catch (Exception ignored) { + // no camp configured — vanID stamping skipped + } + if (campVanID == null && enforceVanID) { + throw new Exception( + "Camp not configured: vanID missing. Please select van/service point in MMU before syncing data."); + } + final Integer vanID = campVanID; + final Integer parkingPlaceID = campParkingPlaceID; + try { if (requestOBJ != null && !requestOBJ.isEmpty()) { JsonObject jsnOBJ = new JsonObject(); @@ -151,10 +183,37 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex // benRegID = rMNCHMBenRegIdMapRepo.getRegID(benDetailsExtraList.get(0).getBenficieryid()); // // if (benRegID != null) { - + + // Build GPS lookup map from i_bendemographics in raw JSON + Map benGpsMap = new HashMap<>(); + JsonArray benJsonArr = jsnOBJ.getAsJsonArray("beneficiaryDetails"); + for (JsonElement el : benJsonArr) { + JsonObject benJson = el.getAsJsonObject(); + if (benJson.has("benficieryid") && !benJson.get("benficieryid").isJsonNull() + && benJson.has("i_bendemographics") + && !benJson.get("i_bendemographics").isJsonNull()) { + benGpsMap.put(benJson.get("benficieryid").getAsBigInteger(), + benJson.getAsJsonObject("i_bendemographics")); + } + } + for (RMNCHBeneficiaryDetailsRmnch obj : benDetailsExtraList) { benRegID = rMNCHMBenRegIdMapRepo.getRegID(obj.getBenficieryid()); obj.setBenRegId(benRegID); + // Extract GPS from i_bendemographics + JsonObject demog = benGpsMap.get(obj.getBenficieryid()); + if (demog != null) { + if (demog.has("latitude") && !demog.get("latitude").isJsonNull()) + obj.setGpsLatitude(demog.get("latitude").getAsDouble()); + if (demog.has("longitude") && !demog.get("longitude").isJsonNull()) + obj.setGpsLongitude(demog.get("longitude").getAsDouble()); + if (demog.has("digipin") && !demog.get("digipin").isJsonNull()) + obj.setDigipin(demog.get("digipin").getAsString()); + if (demog.has("gpsTimestamp") && !demog.get("gpsTimestamp").isJsonNull()) + obj.setGpsTimestamp(new Timestamp(demog.get("gpsTimestamp").getAsLong())); + if (demog.has("isGpsUnavailable") && !demog.get("isGpsUnavailable").isJsonNull()) + obj.setIsGpsUnavailable(demog.get("isGpsUnavailable").getAsBoolean()); + } if(!rMNCHBeneficiaryDetailsRmnchRepo .getByRegID(benRegID).isEmpty()){ RMNCHBeneficiaryDetailsRmnch temp = rMNCHBeneficiaryDetailsRmnchRepo @@ -178,6 +237,10 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex } obj.setRelatedBeneficiaryIdsDB(sb.toString()); } + if (obj.getVanID() == null && vanID != null) { + obj.setVanID(vanID); + obj.setParkingPlaceID(parkingPlaceID); + } if(!rMNCHBenDetailsRepo.getByBenRegID(obj.getBenRegId()).isEmpty()){ RMNCHMBeneficiarydetail rmnchmBeneficiarydetail = rMNCHBenDetailsRepo.getByBenRegID(obj.getBenRegId()).get(0); @@ -208,6 +271,9 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex } + // Keep original list before saveAll — @Transient fields (height/weight/bmi/temperature) + // are lost in the JPA-managed instances returned by merge() + List benDetailsOriginalList = new ArrayList<>(benDetailsExtraList); benDetailsExtraList = (ArrayList) rMNCHBeneficiaryDetailsRmnchRepo .saveAll(benDetailsExtraList); @@ -215,6 +281,22 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex // update beneficiary data in i_beneficiarydetails table rMNCHBenDetailsRepo.saveAll(benDetailsList); + // Write anthropometry (height/weight/bmi/temperature) to i_beneficiarydetails.otherFields. + // i_beneficiarydetails_rmnch has no these columns; FLW-API getBeneficiaryData reads from otherFields. + for (RMNCHBeneficiaryDetailsRmnch obj : benDetailsOriginalList) { + if (obj.getBenRegId() != null && hasAnthropometryData(obj)) { + try { + MBeneficiarydetail benDetail = benDetailRepo.findByBenRegId(obj.getBenRegId()); + if (benDetail != null) { + String merged = mergeAnthropometry(benDetail.getOtherFields(), obj); + benDetailRepo.updateOtherFieldsByBenRegId(obj.getBenRegId(), merged); + } + } catch (Exception ex) { + logger.warn("Failed to update otherFields for benRegId: " + obj.getBenRegId() + " - " + ex.getMessage()); + } + } + } + // born birth details if (jsnOBJ != null && jsnOBJ.has("bornBirthDeatils")) { RMNCHBornBirthDetails[] objArr1 = InputMapper.gson() @@ -228,7 +310,10 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex if (temp != null) obj.setBornBirthDeatilsId(temp.getBornBirthDeatilsId()); } - + if (obj.getVanID() == null && vanID != null) { + obj.setVanID(vanID); + obj.setParkingPlaceID(parkingPlaceID); + } } bornBirthList = (ArrayList) rMNCHBornBirthDetailsRepo .saveAll(bornBirthList); @@ -254,7 +339,10 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex if (temp != null) obj.setCBACDetailsid(temp.getCBACDetailsid()); } - + if (obj.getVanID() == null && vanID != null) { + obj.setVanID(vanID); + obj.setParkingPlaceID(parkingPlaceID); + } } cbacList = (ArrayList) rMNCHCBACDetailsRepo.saveAll(cbacList); @@ -267,6 +355,22 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex .fromJson(jsnOBJ.get("houseHoldDetails"), RMNCHHouseHoldDetails[].class); List houseHoldList = Arrays.asList(objArr3); + // Build gpsTimestamp map (sent as string, needs manual parse) + Map hhTimestampMap = new HashMap<>(); + JsonArray hhJsonArr = jsnOBJ.getAsJsonArray("houseHoldDetails"); + for (JsonElement el : hhJsonArr) { + JsonObject hhJson = el.getAsJsonObject(); + try { + if (hhJson.has("houseoldId") && !hhJson.get("houseoldId").isJsonNull() + && hhJson.has("gpsTimestamp") + && !hhJson.get("gpsTimestamp").isJsonNull()) { + hhTimestampMap.put( + Long.parseLong(hhJson.get("houseoldId").getAsString()), + hhJson.get("gpsTimestamp").getAsLong()); + } + } catch (NumberFormatException ignored) {} + } + for (RMNCHHouseHoldDetails obj : houseHoldList) { if(!rMNCHHouseHoldDetailsRepo .getByHouseHoldID(obj.getHouseoldId()).isEmpty()){ @@ -274,8 +378,13 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex .getByHouseHoldID(obj.getHouseoldId()).get(0); if (temp != null) obj.setHouseHoldDetailsId(temp.getHouseHoldDetailsId()); + if (hhTimestampMap.containsKey(obj.getHouseoldId())) + obj.setGpsTimestamp(new Timestamp(hhTimestampMap.get(obj.getHouseoldId()))); + } + if (obj.getVanID() == null && vanID != null) { + obj.setVanID(vanID); + obj.setParkingPlaceID(parkingPlaceID); } - } houseHoldList = (ArrayList) rMNCHHouseHoldDetailsRepo .saveAll(houseHoldList); @@ -543,6 +652,28 @@ private Integer getInt(JsonObject obj, String key, Integer defaultVal) { ? obj.get(key).getAsInt() : defaultVal; } + + private boolean hasAnthropometryData(RMNCHBeneficiaryDetailsRmnch obj) { + return obj.getHeight() != null || obj.getWeight() != null + || obj.getBmi() != null || obj.getTemperature() != null; + } + + private String mergeAnthropometry(String existingOtherFields, RMNCHBeneficiaryDetailsRmnch obj) { + JsonObject json = new JsonObject(); + if (existingOtherFields != null && !existingOtherFields.isBlank()) { + try { + json = new JsonParser().parse(existingOtherFields).getAsJsonObject(); + } catch (Exception ignored) { + } + } + if (obj.getHeight() != null) json.addProperty("height", obj.getHeight()); + if (obj.getWeight() != null) json.addProperty("weight", obj.getWeight()); + if (obj.getBmi() != null) json.addProperty("bmi", obj.getBmi()); + // mobile sends "temperature"; FLW-API getBeneficiaryData reads "temperatureValue" + if (obj.getTemperature() != null) json.addProperty("temperatureValue", obj.getTemperature()); + return new Gson().toJson(json); + } + @Override public String getBenData(String requestOBJ, String authorisation) throws Exception { String outputResponse = null; @@ -789,6 +920,8 @@ private String getMappingsForAddressIDs(List addressLi benDetailsRMNCHOBJ.setAddressLine2(benAddressOBJ.getPermAddrLine2()); if (benAddressOBJ.getPermAddrLine3() != null) benDetailsRMNCHOBJ.setAddressLine3(benAddressOBJ.getPermAddrLine3()); + if (benAddressOBJ.getPermPinCode() != null) + benDetailsRMNCHOBJ.setPinCode(benAddressOBJ.getPermPinCode()); // related benids if (benDetailsRMNCHOBJ.getRelatedBeneficiaryIdsDB() != null) { diff --git a/src/main/java/com/iemr/common/identity/utils/mapper/InputMapper.java b/src/main/java/com/iemr/common/identity/utils/mapper/InputMapper.java index 4c8db37d..6dbc0301 100644 --- a/src/main/java/com/iemr/common/identity/utils/mapper/InputMapper.java +++ b/src/main/java/com/iemr/common/identity/utils/mapper/InputMapper.java @@ -48,6 +48,11 @@ public InputMapper() { if (builder == null) { builder = new GsonBuilder(); builder.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); + // Timestamp fields (including dob) use Gson's default parsing here, same as + // on vb/stoptb. The gpsTimestamp field on RMNCH entities is parsed by + // com.iemr.common.identity.mapper.GpsTimestampAdapter via a field-level + // @JsonAdapter annotation instead of a global registration, so it can't + // affect any other Timestamp field. } } diff --git a/src/main/java/com/iemr/common/identity/utils/redis/RedisStorage.java b/src/main/java/com/iemr/common/identity/utils/redis/RedisStorage.java index 04a3f1d8..98ced6fa 100644 --- a/src/main/java/com/iemr/common/identity/utils/redis/RedisStorage.java +++ b/src/main/java/com/iemr/common/identity/utils/redis/RedisStorage.java @@ -67,6 +67,13 @@ public String getObject(String key, Boolean extendExpirationTime, int expiration return userRespFromRedis; } + public String getRaw(String key) { + RedisConnection redCon = connection.getConnection(); + byte[] data = redCon.get(key.getBytes()); + redCon.close(); + return data != null ? new String(data) : null; + } + public Long deleteObject(String key) throws RedisSessionException { RedisConnection redCon = connection.getConnection(); Long userRespFromRedis = Long.valueOf(0L); From cd5de787ba9068d4de93648477830b43401c8c05 Mon Sep 17 00:00:00 2001 From: vishwab1 Date: Fri, 17 Jul 2026 10:42:24 +0530 Subject: [PATCH 39/42] feat(household): add totalHhMembers and registeredAtCampSite fields Co-Authored-By: Claude Sonnet 5 --- .../identity/data/rmnch/RMNCHHouseHoldDetails.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java index 7000f6d0..3b842822 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java @@ -114,6 +114,18 @@ public class RMNCHHouseHoldDetails { @Column(name = "familyName") private String familyName; + @Expose + @Column(name = "totalHhMembers") + private Integer totalHhMembers; + + @Expose + @Column(name = "registeredAtCampSite") + private String registeredAtCampSite; + + @Expose + @Column(name = "registeredAtCampSiteId") + private Integer registeredAtCampSiteId; + @Expose @Column(name = "fuelUsed") private String fuelUsed; From 439a64f475e557d4193036328e4652f5ac6bd72a Mon Sep 17 00:00:00 2001 From: vishwab1 Date: Wed, 29 Jul 2026 15:31:17 +0530 Subject: [PATCH 40/42] feat(rmnch): add placeOfCurrentLiving, otherPlaceOfCurrentLiving, institutionName fields --- .../data/rmnch/RMNCHBeneficiaryDetailsRmnch.java | 9 +++++++++ .../identity/data/rmnch/RMNCHMBeneficiarydetail.java | 9 +++++++++ .../identity/service/rmnch/RmnchDataSyncServiceImpl.java | 3 +++ 3 files changed, 21 insertions(+) diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java index 814d2c73..a6604f69 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHBeneficiaryDetailsRmnch.java @@ -532,6 +532,15 @@ public class RMNCHBeneficiaryDetailsRmnch { @Expose private String otherPlaceOfDeath; + @Expose + private String placeOfCurrentLiving; + + @Expose + private String otherPlaceOfCurrentLiving; + + @Expose + private String institutionName; + @Expose private Boolean isSpouseAdded; diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java index 44f15679..0e86127e 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHMBeneficiarydetail.java @@ -222,4 +222,13 @@ public class RMNCHMBeneficiarydetail { @Expose @Column(name = "familyid") private String familyId; + + @Expose + private String placeOfCurrentLiving; + + @Expose + private String otherPlaceOfCurrentLiving; + + @Expose + private String institutionName; } \ No newline at end of file diff --git a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java index 528310d4..afa8155b 100644 --- a/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java +++ b/src/main/java/com/iemr/common/identity/service/rmnch/RmnchDataSyncServiceImpl.java @@ -255,6 +255,9 @@ public String syncDataToAmrit(String requestOBJ, String authorization) throws Ex rmnchmBeneficiarydetail.setGenderId(obj.getGenderId()); rmnchmBeneficiarydetail.setMaritalstatus(obj.getMaritalstatus()); rmnchmBeneficiarydetail.setMaritalstatusId(obj.getMaritalstatusId()); + rmnchmBeneficiarydetail.setPlaceOfCurrentLiving(obj.getPlaceOfCurrentLiving()); + rmnchmBeneficiarydetail.setOtherPlaceOfCurrentLiving(obj.getOtherPlaceOfCurrentLiving()); + rmnchmBeneficiarydetail.setInstitutionName(obj.getInstitutionName()); if(obj.getFamilyId()!=null && !obj.getFamilyId().isEmpty()){ rmnchmBeneficiarydetail.setFamilyId(obj.getFamilyId()); From 5d72275a8ba12269cf0575cc6e97f322f07c9402 Mon Sep 17 00:00:00 2001 From: vishwab1 Date: Mon, 20 Jul 2026 17:05:06 +0530 Subject: [PATCH 41/42] fix(household): accept Pincode key variant during RMNCH sync deserialization FLW-Mobile-App's Household.kt serializes the field as "Pincode" (capital P), but the entity had no @SerializedName so Gson's exact-case field matching against "pincode" silently dropped the value on every sync. Co-Authored-By: Claude Sonnet 5 --- .../iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java index 3b842822..bbfb7725 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java @@ -206,6 +206,7 @@ public class RMNCHHouseHoldDetails { private String other_sourceofDrinkingWater; @Expose + @SerializedName(value = "pincode", alternate = "Pincode") @Column(name = "pincode") private Integer pincode; From f6cc2453942cbc9cfa3d8f2e774119855ef03a75 Mon Sep 17 00:00:00 2001 From: vishwab1 Date: Mon, 20 Jul 2026 17:54:23 +0530 Subject: [PATCH 42/42] feat(household): add address column mapping to i_householddetails New address VARCHAR(500) column added to i_householddetails so household address can be captured once at HH Registration instead of being duplicated per-member on i_beneficiaryaddress. Accepts both "address" and "Address" keys during sync, following the same pattern as the earlier pincode key-case bug. Co-Authored-By: Claude Sonnet 5 --- .../common/identity/data/rmnch/RMNCHHouseHoldDetails.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java index bbfb7725..471bdaa6 100644 --- a/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/common/identity/data/rmnch/RMNCHHouseHoldDetails.java @@ -114,6 +114,11 @@ public class RMNCHHouseHoldDetails { @Column(name = "familyName") private String familyName; + @Expose + @SerializedName(value = "address", alternate = "Address") + @Column(name = "address") + private String address; + @Expose @Column(name = "totalHhMembers") private Integer totalHhMembers;