From bd8f5456bfa84abfc637969e62e242df913eee83 Mon Sep 17 00:00:00 2001 From: Venu-Ajitesh Date: Tue, 29 Apr 2025 12:34:14 +0530 Subject: [PATCH 1/4] FHIR: Renamed medication request full url --- .../converter/OPConsultationConverter.java | 10 +++---- .../dto/compositions/MakeOpComposition.java | 27 ++++++++++--------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/converter/OPConsultationConverter.java b/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/converter/OPConsultationConverter.java index 7ccc8e39..5e40ee4e 100644 --- a/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/converter/OPConsultationConverter.java +++ b/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/converter/OPConsultationConverter.java @@ -455,12 +455,10 @@ private List makeMedicalHistoryList( private List makeAllergiesList( Patient patient, List practitionerList, - OPConsultationRequest opConsultationRequest) - throws ParseException { - return Optional.ofNullable(opConsultationRequest.getAllergies()) - .orElse(Collections.emptyList()) - .stream() - .filter(allergy -> allergy.isBlank() && allergy.isEmpty()) + OPConsultationRequest opConsultationRequest) { + + return Optional.ofNullable(opConsultationRequest.getAllergies()).orElse(List.of()).stream() + .filter(allergy -> allergy != null && !allergy.isBlank()) .map( StreamUtils.wrapException( allergy -> diff --git a/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/dto/compositions/MakeOpComposition.java b/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/dto/compositions/MakeOpComposition.java index 252510ad..b8646ab2 100644 --- a/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/dto/compositions/MakeOpComposition.java +++ b/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/dto/compositions/MakeOpComposition.java @@ -111,7 +111,7 @@ private List makeCompositionSection( List otherObservationList, List documentReferenceList) { List sectionComponentList = new ArrayList<>(); - if (Objects.nonNull(chiefComplaintList)) { + if (chiefComplaintList != null && !chiefComplaintList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -129,7 +129,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(physicalObservationList)) { + if (Objects.nonNull(physicalObservationList) && !physicalObservationList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -149,7 +149,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(allergieList)) { + if (Objects.nonNull(allergieList) && !allergieList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -169,7 +169,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(medicalHistoryList)) { + if (Objects.nonNull(medicalHistoryList) && !medicalHistoryList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -187,7 +187,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(familyMemberHistoryList)) { + if (Objects.nonNull(familyMemberHistoryList) && !familyMemberHistoryList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -205,7 +205,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(investigationAdviceList)) { + if (Objects.nonNull(investigationAdviceList) && !investigationAdviceList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -223,7 +223,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(medicationList)) { + if (Objects.nonNull(medicationList) && !medicationList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -236,11 +236,12 @@ private List makeCompositionSection( for (MedicationRequest medication : medicationList) { sectionComponent.addEntry( new Reference() - .setReference(BundleResourceIdentifier.FAMILY_HISTORY + "/" + medication.getId())); + .setReference( + BundleResourceIdentifier.MEDICATION_REQUEST + "/" + medication.getId())); } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(followupList)) { + if (Objects.nonNull(followupList) && !followupList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -257,7 +258,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(procedureList)) { + if (Objects.nonNull(procedureList) && !procedureList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -274,7 +275,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(referralList)) { + if (Objects.nonNull(referralList) && !referralList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -291,7 +292,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(otherObservationList)) { + if (Objects.nonNull(otherObservationList) && !otherObservationList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -309,7 +310,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(documentReferenceList)) { + if (Objects.nonNull(documentReferenceList) && !documentReferenceList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() From a954b533445c800b4dce595ecc58230bf4635135 Mon Sep 17 00:00:00 2001 From: Venu-Ajitesh Date: Wed, 16 Jul 2025 04:00:30 +0530 Subject: [PATCH 2/4] Fixed linking careContext raceCondition bug and RequestLogV3Service --- .../tables/helpers/FieldIdentifiers.java | 2 + .../mongo/tables/helpers/RequestStatus.java | 10 +- .../mongo/services/RequestLogV3Service.java | 149 +++++++++++------- .../HIPHealthInformationV3Service.java | 90 +++++++---- .../link/hipInitiated/HIPLinkV3Service.java | 18 ++- 5 files changed, 176 insertions(+), 93 deletions(-) diff --git a/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/FieldIdentifiers.java b/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/FieldIdentifiers.java index 851fff63..e02ccbf5 100644 --- a/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/FieldIdentifiers.java +++ b/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/FieldIdentifiers.java @@ -23,6 +23,8 @@ public class FieldIdentifiers { public static final String ENTITY = "entity"; public static final String ENTITY_TYPE = "entityType"; public static final String LAST_UPDATED = "lastUpdated"; + public static final String CREATED_ON = "createdOn"; + public static final String MODULE = "module"; public static final String LINK_TOKEN_REQUEST_ID = "linkTokenRequestId"; // Patient table. diff --git a/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/RequestStatus.java b/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/RequestStatus.java index 351f5d7d..64a7fcc9 100644 --- a/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/RequestStatus.java +++ b/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/RequestStatus.java @@ -53,7 +53,15 @@ public enum RequestStatus { ENCRYPTED_HEALTH_INFORMATION_RECEIVED("Encrypted Health Information received by HIU from HIP"), ENCRYPTED_HEALTH_INFORMATION_ERROR( "Error while receiving encrypted Health Information by HIU from HIP"), - DECRYPTION_ERROR("Unable to decrypt the data sent by HIP"); + DECRYPTION_ERROR("Unable to decrypt the data sent by HIP"), + FETCHING_BUNDLE("Fetching bundle from HIP"), + FETCHING_BUNDLE_ERROR("Error while fetching bundle from HIP"), + FETCHING_BUNDLE_SUCCESS("Bundle fetched successfully from HIP"), + ENCRYPTION_ERROR("Error while encrypting the data"), + ENCRYPTION_SUCCESS("Data encrypted successfully"), + DATA_TRANSFER_INITIATED("Data transfer initiated successfully"), + DATA_TRANSFER_ERROR("Error while initiating data transfer"), + DATA_TRANSFER_SUCCESS("Data transfer completed successfully"); private String value; diff --git a/src/main/java/in/nha/abdm/wrapper/v3/database/mongo/services/RequestLogV3Service.java b/src/main/java/in/nha/abdm/wrapper/v3/database/mongo/services/RequestLogV3Service.java index c6e8cb25..a16be6b7 100644 --- a/src/main/java/in/nha/abdm/wrapper/v3/database/mongo/services/RequestLogV3Service.java +++ b/src/main/java/in/nha/abdm/wrapper/v3/database/mongo/services/RequestLogV3Service.java @@ -29,12 +29,14 @@ import in.nha.abdm.wrapper.v3.hip.hrp.link.userInitiated.responses.InitV3Response; import in.nha.abdm.wrapper.v3.hip.hrp.share.requests.OnShareV3Request; import in.nha.abdm.wrapper.v3.hip.hrp.share.requests.ProfileShareV3Request; +import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; @@ -107,6 +109,17 @@ public void updateError(String requestId, Object errors, RequestStatus requestSt mongoTemplate.updateFirst(query, update, RequestLog.class); } + public void updateConsentStatus(String consentId, Object errors, RequestStatus requestStatus) { + Query query = new Query(Criteria.where(FieldIdentifiers.CONSENT_ID).is(consentId)); + Update update = new Update(); + if (errors != null) { + update.set(FieldIdentifiers.ERROR, errors); + } + update.set(FieldIdentifiers.STATUS, requestStatus); + update.set(FieldIdentifiers.LAST_UPDATED, Utils.getCurrentDateTime()); + mongoTemplate.updateFirst(query, update, RequestLog.class); + } + /** * If any error encountered in the generation of LinkToken API this method is used to update in * requestLogs @@ -241,43 +254,44 @@ public RequestLog findRequestLogByTransactionId(String transactionId) { */ public void persistHipLinkRequest( LinkRecordsV3Request linkRecordsV3Request, RequestStatus status, Object errors) { + if (Objects.isNull(linkRecordsV3Request)) { return; } - RequestLog existingLog = logsRepo.findByClientRequestId(linkRecordsV3Request.getRequestId()); - if (Objects.isNull(existingLog)) { - RequestLog requestLog = new RequestLog(); - requestLog.setAbhaAddress(linkRecordsV3Request.getAbhaAddress()); - requestLog.setModule(FieldIdentifiers.HIP_INITIATED_LINKING); - requestLog.setCreatedOn(Utils.getCurrentDateTime()); - requestLog.setLastUpdated(Utils.getCurrentDateTime()); - requestLog.setClientRequestId(linkRecordsV3Request.getRequestId()); - requestLog.setGatewayRequestId(linkRecordsV3Request.getRequestId()); - requestLog.setHipId(linkRecordsV3Request.getRequesterId()); - requestLog.setStatus(status); - HashMap map = new HashMap<>(); - map.put(FieldIdentifiers.LINK_RECORDS_REQUEST, linkRecordsV3Request); - requestLog.setRequestDetails(map); - if (Objects.nonNull(errors)) { - requestLog.setError(errors); - } - mongoTemplate.save(requestLog); - return; + String requestId = linkRecordsV3Request.getRequestId(); + LocalDateTime now = Utils.getCurrentDateTime(); + + RequestLog existingLog = logsRepo.findByClientRequestId(requestId); + + Map requestDetails = + Optional.ofNullable(existingLog != null ? existingLog.getRequestDetails() : null) + .orElse(new HashMap<>()); + + requestDetails.put(FieldIdentifiers.LINK_RECORDS_REQUEST, linkRecordsV3Request); + + Query query = Query.query(Criteria.where(FieldIdentifiers.CLIENT_REQUEST_ID).is(requestId)); + + Update update = + new Update() + .set(FieldIdentifiers.LAST_UPDATED, now) + .set(FieldIdentifiers.STATUS, status) + .set(FieldIdentifiers.REQUEST_DETAILS, requestDetails); + + if (existingLog == null) { + update + .setOnInsert(FieldIdentifiers.ABHA_ADDRESS, linkRecordsV3Request.getAbhaAddress()) + .setOnInsert(FieldIdentifiers.MODULE, FieldIdentifiers.HIP_INITIATED_LINKING) + .setOnInsert(FieldIdentifiers.CREATED_ON, now) + .setOnInsert(FieldIdentifiers.CLIENT_REQUEST_ID, requestId) + .setOnInsert(FieldIdentifiers.GATEWAY_REQUEST_ID, requestId) + .setOnInsert(FieldIdentifiers.HIP_ID, linkRecordsV3Request.getRequesterId()); } - Query query = - new Query( - Criteria.where(FieldIdentifiers.CLIENT_REQUEST_ID) - .is(linkRecordsV3Request.getRequestId())); - Map map = existingLog.getRequestDetails(); - if (Objects.isNull(map)) { - map = new HashMap<>(); + + if (Objects.nonNull(errors)) { + update.set(FieldIdentifiers.ERROR, errors); } - map.replace(FieldIdentifiers.LINK_RECORDS_REQUEST, linkRecordsV3Request); - Update update = new Update(); - update.set(FieldIdentifiers.REQUEST_DETAILS, map); - update.set(FieldIdentifiers.STATUS, status); - update.set(FieldIdentifiers.LAST_UPDATED, Utils.getCurrentDateTime()); - mongoTemplate.updateFirst(query, update, RequestLog.class); + + mongoTemplate.upsert(query, update, RequestLog.class); } /** @@ -602,38 +616,57 @@ public void saveLinkTokenRequest( * *

Adding linkOnAddCareContextsResponse dump into db. * - * @param linkOnAddCareContextsV3Response Acknowledgement from ABDM gateway for HipLinking. + * @param response Acknowledgement from ABDM gateway for HipLinking. */ - public void setHipOnAddCareContextResponse( - LinkOnAddCareContextsV3Response linkOnAddCareContextsV3Response) + public void setHipOnAddCareContextResponse(LinkOnAddCareContextsV3Response response) throws IllegalDataStateException { - RequestLog RequestLog = - logsRepo.findByGatewayRequestId( - linkOnAddCareContextsV3Response.getResponse().getRequestId()); - if (RequestLog == null) { - throw new IllegalDataStateException( - "Request not found in database for: " - + linkOnAddCareContextsV3Response.getResponse().getRequestId()); - } - HashMap map = RequestLog.getRequestDetails(); - map.put(FieldIdentifiers.HIP_ON_ADD_CARE_CONTEXT_RESPONSE, linkOnAddCareContextsV3Response); - Query query = - new Query( - Criteria.where(FieldIdentifiers.GATEWAY_REQUEST_ID) - .is(linkOnAddCareContextsV3Response.getResponse().getRequestId())); - Update update = new Update(); - if ((Objects.nonNull(linkOnAddCareContextsV3Response.getError()))) { - update.set(FieldIdentifiers.ERROR, linkOnAddCareContextsV3Response.getError()); + String requestId = response.getResponse().getRequestId(); + log.info("Processing HIP OnAddCareContext response for requestId: {}", requestId); + + Query query = Query.query(Criteria.where(FieldIdentifiers.GATEWAY_REQUEST_ID).is(requestId)); + Update update = + new Update() + .set( + FieldIdentifiers.REQUEST_DETAILS + + "." + + FieldIdentifiers.HIP_ON_ADD_CARE_CONTEXT_RESPONSE, + response) + .set(FieldIdentifiers.LAST_UPDATED, Utils.getCurrentDateTime()); + + if (response.getError() != null) { + update.set(FieldIdentifiers.ERROR, response.getError()); } else { update.set(FieldIdentifiers.STATUS, RequestStatus.CARE_CONTEXT_LINKED); - LinkRecordsV3Request linkRecordsV3Request = - (LinkRecordsV3Request) - RequestLog.getRequestDetails().get(FieldIdentifiers.LINK_RECORDS_REQUEST); - patientService.addPatientCareContexts(linkRecordsV3Request); } - update.set(FieldIdentifiers.REQUEST_DETAILS, map); - mongoTemplate.updateFirst(query, update, RequestLog.class); + log.info("Querying gatewayRequestId = {}", requestId); + log.info("Query for requestId: {} {}", query, requestId); + log.info("Update for requestId: {} {}", update, requestId); + RequestLog updatedLog = + mongoTemplate.findAndModify( + query, update, FindAndModifyOptions.options().returnNew(true), RequestLog.class); + + if (updatedLog == null) { + log.warn( + "findAndModify returned null, fallback to fetch manually for requestId: {}", requestId); + updatedLog = logsRepo.findByGatewayRequestId(requestId); + + if (updatedLog == null) { + throw new IllegalDataStateException("Request not found in database for: " + requestId); + } + } + + if (response.getError() == null) { + Object raw = updatedLog.getRequestDetails().get(FieldIdentifiers.LINK_RECORDS_REQUEST); + if (raw instanceof LinkRecordsV3Request) { + patientService.addPatientCareContexts((LinkRecordsV3Request) raw); + } else { + log.warn( + "Expected LinkRecordsV3Request but got: {}", + raw == null ? "null" : raw.getClass().getName()); + } + } + log.info("Successfully updated requestId: {}", requestId); } public RequestLog getLogsByAbhaAddress(String abhaAddress, String hipId) { diff --git a/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/dataTransfer/HIPHealthInformationV3Service.java b/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/dataTransfer/HIPHealthInformationV3Service.java index ebf522e2..f2fec9d1 100644 --- a/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/dataTransfer/HIPHealthInformationV3Service.java +++ b/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/dataTransfer/HIPHealthInformationV3Service.java @@ -7,6 +7,7 @@ import in.nha.abdm.wrapper.v1.common.models.RespRequest; import in.nha.abdm.wrapper.v1.common.requests.*; import in.nha.abdm.wrapper.v1.common.responses.ErrorResponse; +import in.nha.abdm.wrapper.v1.common.responses.ErrorV3Response; import in.nha.abdm.wrapper.v1.common.responses.GenericResponse; import in.nha.abdm.wrapper.v1.hip.hrp.consent.requests.HIPNotifyRequest; import in.nha.abdm.wrapper.v1.hip.hrp.dataTransfer.callback.HIPHealthInformationRequest; @@ -27,6 +28,7 @@ import in.nha.abdm.wrapper.v3.common.RequestV3Manager; import in.nha.abdm.wrapper.v3.common.exceptions.BadRequestHandler; import in.nha.abdm.wrapper.v3.common.models.GenericV3Response; +import in.nha.abdm.wrapper.v3.config.ErrorHandler; import in.nha.abdm.wrapper.v3.database.mongo.services.ConsentPatientV3Service; import in.nha.abdm.wrapper.v3.database.mongo.services.PatientV3Service; import in.nha.abdm.wrapper.v3.database.mongo.services.RequestLogV3Service; @@ -146,20 +148,32 @@ public void healthInformation( // Acknowledge to gateway that health information request has been received. healthInformationAcknowledgementRequest( hipHealthInformationRequest, onHealthInformationRequest, headers); + try { + // Sending the data to HIU only if there is no errors + if (Objects.isNull(onHealthInformationRequest.getError())) { + // Prepare health information bundle request which needs to be sent to HIU. + HealthInformationBundleResponse healthInformationBundleResponse = + fetchHealthInformationBundle(hipHealthInformationRequest, headers); + // Push the health information to HIU. + List> pushHealthInformationResponse = + pushHealthInformation(healthInformationBundleResponse, consentId, headers); + // Notify Gateway that health information was pushed to HIU. + healthInformationPushNotify( + hipHealthInformationRequest, consentId, pushHealthInformationResponse, headers); + } else { + // Sending BAD_REQUEST since there are some errors earlier + healthInformationPushNotify( + hipHealthInformationRequest, + consentId, + Collections.singletonList(new ResponseEntity<>(HttpStatus.BAD_REQUEST)), + headers); + } + } catch (Exception e) { + List errors = ErrorHandler.getErrors(e.getMessage()); + log.debug(errors); + requestLogV3Service.updateConsentStatus(consentId, errors, RequestStatus.DATA_TRANSFER_ERROR); - // Sending the data to HIU only if there is no errors - if (Objects.isNull(onHealthInformationRequest.getError())) { - // Prepare health information bundle request which needs to be sent to HIU. - HealthInformationBundleResponse healthInformationBundleResponse = - fetchHealthInformationBundle(hipHealthInformationRequest, headers); - // Push the health information to HIU. - List> pushHealthInformationResponse = - pushHealthInformation(healthInformationBundleResponse, consentId, headers); - // Notify Gateway that health information was pushed to HIU. - healthInformationPushNotify( - hipHealthInformationRequest, consentId, pushHealthInformationResponse, headers); - } else { - // Sending BAD_REQUEST since there are some errors earlier + // Notify Gateway that health information was pushed to HIU with BAD_REQUEST status. healthInformationPushNotify( hipHealthInformationRequest, consentId, @@ -212,27 +226,30 @@ private void healthInformationAcknowledgementRequest( private HealthInformationBundleResponse fetchHealthInformationBundle( HIPHealthInformationRequest hipHealthInformationRequest, HttpHeaders headers) throws IllegalDataStateException { - ConsentCareContextMapping existingLog = + ConsentCareContextMapping existingConsentLog = consentCareContextsService.findMappingByConsentId( hipHealthInformationRequest.getHiRequest().getConsent().getId()); + RequestLog existingLog = + requestLogV3Service.findByConsentId( + hipHealthInformationRequest.getHiRequest().getConsent().getId(), + GatewayConstants.HIP, + headers.getFirst(GatewayConstants.X_HIP_ID)); + if (existingLog == null) { + throw new IllegalDataStateException("Request log not found for consent id"); + } HIPNotifyRequest hipNotifyRequest = - (HIPNotifyRequest) - requestLogV3Service - .findByConsentId( - hipHealthInformationRequest.getHiRequest().getConsent().getId(), - GatewayConstants.HIP, - headers.getFirst(GatewayConstants.X_HIP_ID)) - .getRequestDetails() - .get(FieldIdentifiers.HIP_NOTIFY_REQUEST); + (HIPNotifyRequest) existingLog.getRequestDetails().get(FieldIdentifiers.HIP_NOTIFY_REQUEST); String hipId = hipNotifyRequest.getNotification().getConsentDetail().getHip().getId(); - if (existingLog == null) { + if (existingConsentLog == null) { throw new IllegalDataStateException("consent id not found in db"); } HealthInformationBundleRequest healthInformationBundleRequest = HealthInformationBundleRequest.builder() .hipId(hipId) - .careContextsWithPatientReferences(existingLog.getCareContexts()) + .careContextsWithPatientReferences(existingConsentLog.getCareContexts()) .build(); + requestLogV3Service.updateConsentStatus( + existingConsentLog.getConsentId(), null, RequestStatus.FETCHING_BUNDLE); log.debug( "Health information bundle request HIP : " + healthInformationBundleRequest.toString()); return hipClient.healthInformationBundleRequest(healthInformationBundleRequest).getBody(); @@ -298,6 +315,9 @@ private List fetchHealthInformationPushRequest( EncryptionResponse encryptedData = encryptionService.encrypt(hipHealthInformationRequest, healthInformationBundleResponse); + requestLogV3Service.updateConsentStatus( + hipNotifyRequest.getNotification().getConsentId(), null, RequestStatus.ENCRYPTION_SUCCESS); + HealthInformationDhPublicKey receiverDhPublicKey = hipHealthInformationRequest.getHiRequest().getKeyMaterial().getDhPublicKey(); @@ -362,7 +382,8 @@ private void healthInformationPushNotify( HIPHealthInformationRequest hipHealthInformationRequest, String consentId, List> pushHealthInformationResponse, - HttpHeaders headers) { + HttpHeaders headers) + throws IllegalDataStateException { boolean allSuccess = pushHealthInformationResponse.stream() .allMatch(response -> response.getStatusCode().is2xxSuccessful()); @@ -370,13 +391,14 @@ private void healthInformationPushNotify( String healthInformationStatus = allSuccess ? "DELIVERED" : "ERRORED"; String sessionStatus = allSuccess ? "TRANSFERRED" : "FAILED"; + RequestLog existingLog = + requestLogV3Service.findByConsentId( + consentId, GatewayConstants.HIP, headers.getFirst(GatewayConstants.X_HIP_ID)); + if (existingLog == null) { + throw new IllegalDataStateException("Request log not found for consent id: " + consentId); + } HIPNotifyRequest hipNotifyRequest = - (HIPNotifyRequest) - requestLogV3Service - .findByConsentId( - consentId, GatewayConstants.HIP, headers.getFirst(GatewayConstants.X_HIP_ID)) - .getRequestDetails() - .get(FieldIdentifiers.HIP_NOTIFY_REQUEST); + (HIPNotifyRequest) existingLog.getRequestDetails().get(FieldIdentifiers.HIP_NOTIFY_REQUEST); List listOfCareContexts = hipNotifyRequest.getNotification().getConsentDetail().getCareContexts(); List healthInformationStatusResponseList = new ArrayList<>(); @@ -415,6 +437,12 @@ private void healthInformationPushNotify( .notification(healthInformationNotificationStatus) .build(); log.info(healthInformationPushNotification.toString()); + if (allSuccess) { + requestLogV3Service.updateConsentStatus(consentId, null, RequestStatus.DATA_TRANSFER_SUCCESS); + } else { + requestLogV3Service.updateConsentStatus(consentId, null, RequestStatus.DATA_TRANSFER_ERROR); + log.error("Data transfer failed for consent id: " + consentId); + } try { ResponseEntity response = requestV3Manager.fetchResponseFromGateway( diff --git a/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/link/hipInitiated/HIPLinkV3Service.java b/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/link/hipInitiated/HIPLinkV3Service.java index 336cb991..9c587a20 100644 --- a/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/link/hipInitiated/HIPLinkV3Service.java +++ b/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/link/hipInitiated/HIPLinkV3Service.java @@ -99,7 +99,7 @@ public FacadeV3Response addCareContexts(LinkRecordsV3Request linkRecordsV3Reques linkRecordsV3Request.getRequesterId(), linkRecordsV3Request.getCareContexts()); - if (Objects.nonNull(sameCareContexts)) { + if (Objects.nonNull(sameCareContexts) && !sameCareContexts.isEmpty()) { return hipContextNotify(linkRecordsV3Request, patient, sameCareContexts); } @@ -153,6 +153,7 @@ private List buildPatientCareContextHIType( private FacadeV3Response sendAddCareContextsRequest( LinkRecordsV3Request request, AddCareContexts addCareContexts, String linkToken) { try { + requestLogV3Service.persistHipLinkRequest(request, RequestStatus.INITIATING, null); ResponseEntity response = requestV3Manager.fetchResponseFromGateway( addCareContextsPath, @@ -210,6 +211,15 @@ private FacadeV3Response buildErrorResponse( .build(); } + private FacadeV3Response buildErrorResponse( + LinkRecordsV3Request request, List errors) { + return FacadeV3Response.builder() + .clientRequestId(request.getRequestId()) + .httpStatusCode(HttpStatus.BAD_REQUEST) + .errors(errors) + .build(); + } + private FacadeV3Response handleAddCareContextError(LinkRecordsV3Request request) { ErrorResponse errorResponse = ErrorResponse.builder() @@ -228,8 +238,10 @@ private FacadeV3Response handleAddCareContextError(LinkRecordsV3Request request) private FacadeV3Response handleWebClientBadRequest( LinkRecordsV3Request request, WebClientResponseException.BadRequest ex) { Object error = BadRequestHandler.getError(ex); - requestLogV3Service.persistHipLinkRequest(request, RequestStatus.ADD_CARE_CONTEXT_ERROR, error); - return buildErrorResponse(request, "Wrapper-1001", ex.getMessage()); + List errorList = ErrorHandler.getErrors(error); + requestLogV3Service.persistHipLinkRequest( + request, RequestStatus.ADD_CARE_CONTEXT_ERROR, errorList); + return buildErrorResponse(request, errorList); } private FacadeV3Response handleGeneralException(LinkRecordsV3Request request, Exception ex) { From 0e9650155b080c333d4cdc364994e439ff1fa041 Mon Sep 17 00:00:00 2001 From: Venu-Ajitesh Date: Tue, 29 Apr 2025 12:34:14 +0530 Subject: [PATCH 3/4] FHIR: Renamed medication request full url --- .../converter/OPConsultationConverter.java | 10 +++---- .../dto/compositions/MakeOpComposition.java | 27 ++++++++++--------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/converter/OPConsultationConverter.java b/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/converter/OPConsultationConverter.java index 7ccc8e39..5e40ee4e 100644 --- a/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/converter/OPConsultationConverter.java +++ b/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/converter/OPConsultationConverter.java @@ -455,12 +455,10 @@ private List makeMedicalHistoryList( private List makeAllergiesList( Patient patient, List practitionerList, - OPConsultationRequest opConsultationRequest) - throws ParseException { - return Optional.ofNullable(opConsultationRequest.getAllergies()) - .orElse(Collections.emptyList()) - .stream() - .filter(allergy -> allergy.isBlank() && allergy.isEmpty()) + OPConsultationRequest opConsultationRequest) { + + return Optional.ofNullable(opConsultationRequest.getAllergies()).orElse(List.of()).stream() + .filter(allergy -> allergy != null && !allergy.isBlank()) .map( StreamUtils.wrapException( allergy -> diff --git a/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/dto/compositions/MakeOpComposition.java b/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/dto/compositions/MakeOpComposition.java index 252510ad..b8646ab2 100644 --- a/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/dto/compositions/MakeOpComposition.java +++ b/fhir-mapper/src/main/java/com/nha/abdm/fhir/mapper/rest/dto/compositions/MakeOpComposition.java @@ -111,7 +111,7 @@ private List makeCompositionSection( List otherObservationList, List documentReferenceList) { List sectionComponentList = new ArrayList<>(); - if (Objects.nonNull(chiefComplaintList)) { + if (chiefComplaintList != null && !chiefComplaintList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -129,7 +129,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(physicalObservationList)) { + if (Objects.nonNull(physicalObservationList) && !physicalObservationList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -149,7 +149,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(allergieList)) { + if (Objects.nonNull(allergieList) && !allergieList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -169,7 +169,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(medicalHistoryList)) { + if (Objects.nonNull(medicalHistoryList) && !medicalHistoryList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -187,7 +187,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(familyMemberHistoryList)) { + if (Objects.nonNull(familyMemberHistoryList) && !familyMemberHistoryList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -205,7 +205,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(investigationAdviceList)) { + if (Objects.nonNull(investigationAdviceList) && !investigationAdviceList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -223,7 +223,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(medicationList)) { + if (Objects.nonNull(medicationList) && !medicationList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -236,11 +236,12 @@ private List makeCompositionSection( for (MedicationRequest medication : medicationList) { sectionComponent.addEntry( new Reference() - .setReference(BundleResourceIdentifier.FAMILY_HISTORY + "/" + medication.getId())); + .setReference( + BundleResourceIdentifier.MEDICATION_REQUEST + "/" + medication.getId())); } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(followupList)) { + if (Objects.nonNull(followupList) && !followupList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -257,7 +258,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(procedureList)) { + if (Objects.nonNull(procedureList) && !procedureList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -274,7 +275,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(referralList)) { + if (Objects.nonNull(referralList) && !referralList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -291,7 +292,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(otherObservationList)) { + if (Objects.nonNull(otherObservationList) && !otherObservationList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() @@ -309,7 +310,7 @@ private List makeCompositionSection( } sectionComponentList.add(sectionComponent); } - if (Objects.nonNull(documentReferenceList)) { + if (Objects.nonNull(documentReferenceList) && !documentReferenceList.isEmpty()) { Composition.SectionComponent sectionComponent = new Composition.SectionComponent(); sectionComponent.setCode( new CodeableConcept() From 556271269649c68b0ab7d7d27a8288bd2629f38f Mon Sep 17 00:00:00 2001 From: Venu-Ajitesh Date: Wed, 16 Jul 2025 04:00:30 +0530 Subject: [PATCH 4/4] Fixed linking careContext raceCondition bug and RequestLogV3Service --- .../tables/helpers/FieldIdentifiers.java | 2 + .../mongo/tables/helpers/RequestStatus.java | 10 +- .../mongo/services/RequestLogV3Service.java | 149 +++++++++++------- .../HIPHealthInformationV3Service.java | 90 +++++++---- .../link/hipInitiated/HIPLinkV3Service.java | 15 +- 5 files changed, 168 insertions(+), 98 deletions(-) diff --git a/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/FieldIdentifiers.java b/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/FieldIdentifiers.java index 851fff63..e02ccbf5 100644 --- a/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/FieldIdentifiers.java +++ b/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/FieldIdentifiers.java @@ -23,6 +23,8 @@ public class FieldIdentifiers { public static final String ENTITY = "entity"; public static final String ENTITY_TYPE = "entityType"; public static final String LAST_UPDATED = "lastUpdated"; + public static final String CREATED_ON = "createdOn"; + public static final String MODULE = "module"; public static final String LINK_TOKEN_REQUEST_ID = "linkTokenRequestId"; // Patient table. diff --git a/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/RequestStatus.java b/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/RequestStatus.java index 351f5d7d..64a7fcc9 100644 --- a/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/RequestStatus.java +++ b/src/main/java/in/nha/abdm/wrapper/v1/hip/hrp/database/mongo/tables/helpers/RequestStatus.java @@ -53,7 +53,15 @@ public enum RequestStatus { ENCRYPTED_HEALTH_INFORMATION_RECEIVED("Encrypted Health Information received by HIU from HIP"), ENCRYPTED_HEALTH_INFORMATION_ERROR( "Error while receiving encrypted Health Information by HIU from HIP"), - DECRYPTION_ERROR("Unable to decrypt the data sent by HIP"); + DECRYPTION_ERROR("Unable to decrypt the data sent by HIP"), + FETCHING_BUNDLE("Fetching bundle from HIP"), + FETCHING_BUNDLE_ERROR("Error while fetching bundle from HIP"), + FETCHING_BUNDLE_SUCCESS("Bundle fetched successfully from HIP"), + ENCRYPTION_ERROR("Error while encrypting the data"), + ENCRYPTION_SUCCESS("Data encrypted successfully"), + DATA_TRANSFER_INITIATED("Data transfer initiated successfully"), + DATA_TRANSFER_ERROR("Error while initiating data transfer"), + DATA_TRANSFER_SUCCESS("Data transfer completed successfully"); private String value; diff --git a/src/main/java/in/nha/abdm/wrapper/v3/database/mongo/services/RequestLogV3Service.java b/src/main/java/in/nha/abdm/wrapper/v3/database/mongo/services/RequestLogV3Service.java index c6e8cb25..a16be6b7 100644 --- a/src/main/java/in/nha/abdm/wrapper/v3/database/mongo/services/RequestLogV3Service.java +++ b/src/main/java/in/nha/abdm/wrapper/v3/database/mongo/services/RequestLogV3Service.java @@ -29,12 +29,14 @@ import in.nha.abdm.wrapper.v3.hip.hrp.link.userInitiated.responses.InitV3Response; import in.nha.abdm.wrapper.v3.hip.hrp.share.requests.OnShareV3Request; import in.nha.abdm.wrapper.v3.hip.hrp.share.requests.ProfileShareV3Request; +import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; @@ -107,6 +109,17 @@ public void updateError(String requestId, Object errors, RequestStatus requestSt mongoTemplate.updateFirst(query, update, RequestLog.class); } + public void updateConsentStatus(String consentId, Object errors, RequestStatus requestStatus) { + Query query = new Query(Criteria.where(FieldIdentifiers.CONSENT_ID).is(consentId)); + Update update = new Update(); + if (errors != null) { + update.set(FieldIdentifiers.ERROR, errors); + } + update.set(FieldIdentifiers.STATUS, requestStatus); + update.set(FieldIdentifiers.LAST_UPDATED, Utils.getCurrentDateTime()); + mongoTemplate.updateFirst(query, update, RequestLog.class); + } + /** * If any error encountered in the generation of LinkToken API this method is used to update in * requestLogs @@ -241,43 +254,44 @@ public RequestLog findRequestLogByTransactionId(String transactionId) { */ public void persistHipLinkRequest( LinkRecordsV3Request linkRecordsV3Request, RequestStatus status, Object errors) { + if (Objects.isNull(linkRecordsV3Request)) { return; } - RequestLog existingLog = logsRepo.findByClientRequestId(linkRecordsV3Request.getRequestId()); - if (Objects.isNull(existingLog)) { - RequestLog requestLog = new RequestLog(); - requestLog.setAbhaAddress(linkRecordsV3Request.getAbhaAddress()); - requestLog.setModule(FieldIdentifiers.HIP_INITIATED_LINKING); - requestLog.setCreatedOn(Utils.getCurrentDateTime()); - requestLog.setLastUpdated(Utils.getCurrentDateTime()); - requestLog.setClientRequestId(linkRecordsV3Request.getRequestId()); - requestLog.setGatewayRequestId(linkRecordsV3Request.getRequestId()); - requestLog.setHipId(linkRecordsV3Request.getRequesterId()); - requestLog.setStatus(status); - HashMap map = new HashMap<>(); - map.put(FieldIdentifiers.LINK_RECORDS_REQUEST, linkRecordsV3Request); - requestLog.setRequestDetails(map); - if (Objects.nonNull(errors)) { - requestLog.setError(errors); - } - mongoTemplate.save(requestLog); - return; + String requestId = linkRecordsV3Request.getRequestId(); + LocalDateTime now = Utils.getCurrentDateTime(); + + RequestLog existingLog = logsRepo.findByClientRequestId(requestId); + + Map requestDetails = + Optional.ofNullable(existingLog != null ? existingLog.getRequestDetails() : null) + .orElse(new HashMap<>()); + + requestDetails.put(FieldIdentifiers.LINK_RECORDS_REQUEST, linkRecordsV3Request); + + Query query = Query.query(Criteria.where(FieldIdentifiers.CLIENT_REQUEST_ID).is(requestId)); + + Update update = + new Update() + .set(FieldIdentifiers.LAST_UPDATED, now) + .set(FieldIdentifiers.STATUS, status) + .set(FieldIdentifiers.REQUEST_DETAILS, requestDetails); + + if (existingLog == null) { + update + .setOnInsert(FieldIdentifiers.ABHA_ADDRESS, linkRecordsV3Request.getAbhaAddress()) + .setOnInsert(FieldIdentifiers.MODULE, FieldIdentifiers.HIP_INITIATED_LINKING) + .setOnInsert(FieldIdentifiers.CREATED_ON, now) + .setOnInsert(FieldIdentifiers.CLIENT_REQUEST_ID, requestId) + .setOnInsert(FieldIdentifiers.GATEWAY_REQUEST_ID, requestId) + .setOnInsert(FieldIdentifiers.HIP_ID, linkRecordsV3Request.getRequesterId()); } - Query query = - new Query( - Criteria.where(FieldIdentifiers.CLIENT_REQUEST_ID) - .is(linkRecordsV3Request.getRequestId())); - Map map = existingLog.getRequestDetails(); - if (Objects.isNull(map)) { - map = new HashMap<>(); + + if (Objects.nonNull(errors)) { + update.set(FieldIdentifiers.ERROR, errors); } - map.replace(FieldIdentifiers.LINK_RECORDS_REQUEST, linkRecordsV3Request); - Update update = new Update(); - update.set(FieldIdentifiers.REQUEST_DETAILS, map); - update.set(FieldIdentifiers.STATUS, status); - update.set(FieldIdentifiers.LAST_UPDATED, Utils.getCurrentDateTime()); - mongoTemplate.updateFirst(query, update, RequestLog.class); + + mongoTemplate.upsert(query, update, RequestLog.class); } /** @@ -602,38 +616,57 @@ public void saveLinkTokenRequest( * *

Adding linkOnAddCareContextsResponse dump into db. * - * @param linkOnAddCareContextsV3Response Acknowledgement from ABDM gateway for HipLinking. + * @param response Acknowledgement from ABDM gateway for HipLinking. */ - public void setHipOnAddCareContextResponse( - LinkOnAddCareContextsV3Response linkOnAddCareContextsV3Response) + public void setHipOnAddCareContextResponse(LinkOnAddCareContextsV3Response response) throws IllegalDataStateException { - RequestLog RequestLog = - logsRepo.findByGatewayRequestId( - linkOnAddCareContextsV3Response.getResponse().getRequestId()); - if (RequestLog == null) { - throw new IllegalDataStateException( - "Request not found in database for: " - + linkOnAddCareContextsV3Response.getResponse().getRequestId()); - } - HashMap map = RequestLog.getRequestDetails(); - map.put(FieldIdentifiers.HIP_ON_ADD_CARE_CONTEXT_RESPONSE, linkOnAddCareContextsV3Response); - Query query = - new Query( - Criteria.where(FieldIdentifiers.GATEWAY_REQUEST_ID) - .is(linkOnAddCareContextsV3Response.getResponse().getRequestId())); - Update update = new Update(); - if ((Objects.nonNull(linkOnAddCareContextsV3Response.getError()))) { - update.set(FieldIdentifiers.ERROR, linkOnAddCareContextsV3Response.getError()); + String requestId = response.getResponse().getRequestId(); + log.info("Processing HIP OnAddCareContext response for requestId: {}", requestId); + + Query query = Query.query(Criteria.where(FieldIdentifiers.GATEWAY_REQUEST_ID).is(requestId)); + Update update = + new Update() + .set( + FieldIdentifiers.REQUEST_DETAILS + + "." + + FieldIdentifiers.HIP_ON_ADD_CARE_CONTEXT_RESPONSE, + response) + .set(FieldIdentifiers.LAST_UPDATED, Utils.getCurrentDateTime()); + + if (response.getError() != null) { + update.set(FieldIdentifiers.ERROR, response.getError()); } else { update.set(FieldIdentifiers.STATUS, RequestStatus.CARE_CONTEXT_LINKED); - LinkRecordsV3Request linkRecordsV3Request = - (LinkRecordsV3Request) - RequestLog.getRequestDetails().get(FieldIdentifiers.LINK_RECORDS_REQUEST); - patientService.addPatientCareContexts(linkRecordsV3Request); } - update.set(FieldIdentifiers.REQUEST_DETAILS, map); - mongoTemplate.updateFirst(query, update, RequestLog.class); + log.info("Querying gatewayRequestId = {}", requestId); + log.info("Query for requestId: {} {}", query, requestId); + log.info("Update for requestId: {} {}", update, requestId); + RequestLog updatedLog = + mongoTemplate.findAndModify( + query, update, FindAndModifyOptions.options().returnNew(true), RequestLog.class); + + if (updatedLog == null) { + log.warn( + "findAndModify returned null, fallback to fetch manually for requestId: {}", requestId); + updatedLog = logsRepo.findByGatewayRequestId(requestId); + + if (updatedLog == null) { + throw new IllegalDataStateException("Request not found in database for: " + requestId); + } + } + + if (response.getError() == null) { + Object raw = updatedLog.getRequestDetails().get(FieldIdentifiers.LINK_RECORDS_REQUEST); + if (raw instanceof LinkRecordsV3Request) { + patientService.addPatientCareContexts((LinkRecordsV3Request) raw); + } else { + log.warn( + "Expected LinkRecordsV3Request but got: {}", + raw == null ? "null" : raw.getClass().getName()); + } + } + log.info("Successfully updated requestId: {}", requestId); } public RequestLog getLogsByAbhaAddress(String abhaAddress, String hipId) { diff --git a/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/dataTransfer/HIPHealthInformationV3Service.java b/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/dataTransfer/HIPHealthInformationV3Service.java index ebf522e2..f2fec9d1 100644 --- a/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/dataTransfer/HIPHealthInformationV3Service.java +++ b/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/dataTransfer/HIPHealthInformationV3Service.java @@ -7,6 +7,7 @@ import in.nha.abdm.wrapper.v1.common.models.RespRequest; import in.nha.abdm.wrapper.v1.common.requests.*; import in.nha.abdm.wrapper.v1.common.responses.ErrorResponse; +import in.nha.abdm.wrapper.v1.common.responses.ErrorV3Response; import in.nha.abdm.wrapper.v1.common.responses.GenericResponse; import in.nha.abdm.wrapper.v1.hip.hrp.consent.requests.HIPNotifyRequest; import in.nha.abdm.wrapper.v1.hip.hrp.dataTransfer.callback.HIPHealthInformationRequest; @@ -27,6 +28,7 @@ import in.nha.abdm.wrapper.v3.common.RequestV3Manager; import in.nha.abdm.wrapper.v3.common.exceptions.BadRequestHandler; import in.nha.abdm.wrapper.v3.common.models.GenericV3Response; +import in.nha.abdm.wrapper.v3.config.ErrorHandler; import in.nha.abdm.wrapper.v3.database.mongo.services.ConsentPatientV3Service; import in.nha.abdm.wrapper.v3.database.mongo.services.PatientV3Service; import in.nha.abdm.wrapper.v3.database.mongo.services.RequestLogV3Service; @@ -146,20 +148,32 @@ public void healthInformation( // Acknowledge to gateway that health information request has been received. healthInformationAcknowledgementRequest( hipHealthInformationRequest, onHealthInformationRequest, headers); + try { + // Sending the data to HIU only if there is no errors + if (Objects.isNull(onHealthInformationRequest.getError())) { + // Prepare health information bundle request which needs to be sent to HIU. + HealthInformationBundleResponse healthInformationBundleResponse = + fetchHealthInformationBundle(hipHealthInformationRequest, headers); + // Push the health information to HIU. + List> pushHealthInformationResponse = + pushHealthInformation(healthInformationBundleResponse, consentId, headers); + // Notify Gateway that health information was pushed to HIU. + healthInformationPushNotify( + hipHealthInformationRequest, consentId, pushHealthInformationResponse, headers); + } else { + // Sending BAD_REQUEST since there are some errors earlier + healthInformationPushNotify( + hipHealthInformationRequest, + consentId, + Collections.singletonList(new ResponseEntity<>(HttpStatus.BAD_REQUEST)), + headers); + } + } catch (Exception e) { + List errors = ErrorHandler.getErrors(e.getMessage()); + log.debug(errors); + requestLogV3Service.updateConsentStatus(consentId, errors, RequestStatus.DATA_TRANSFER_ERROR); - // Sending the data to HIU only if there is no errors - if (Objects.isNull(onHealthInformationRequest.getError())) { - // Prepare health information bundle request which needs to be sent to HIU. - HealthInformationBundleResponse healthInformationBundleResponse = - fetchHealthInformationBundle(hipHealthInformationRequest, headers); - // Push the health information to HIU. - List> pushHealthInformationResponse = - pushHealthInformation(healthInformationBundleResponse, consentId, headers); - // Notify Gateway that health information was pushed to HIU. - healthInformationPushNotify( - hipHealthInformationRequest, consentId, pushHealthInformationResponse, headers); - } else { - // Sending BAD_REQUEST since there are some errors earlier + // Notify Gateway that health information was pushed to HIU with BAD_REQUEST status. healthInformationPushNotify( hipHealthInformationRequest, consentId, @@ -212,27 +226,30 @@ private void healthInformationAcknowledgementRequest( private HealthInformationBundleResponse fetchHealthInformationBundle( HIPHealthInformationRequest hipHealthInformationRequest, HttpHeaders headers) throws IllegalDataStateException { - ConsentCareContextMapping existingLog = + ConsentCareContextMapping existingConsentLog = consentCareContextsService.findMappingByConsentId( hipHealthInformationRequest.getHiRequest().getConsent().getId()); + RequestLog existingLog = + requestLogV3Service.findByConsentId( + hipHealthInformationRequest.getHiRequest().getConsent().getId(), + GatewayConstants.HIP, + headers.getFirst(GatewayConstants.X_HIP_ID)); + if (existingLog == null) { + throw new IllegalDataStateException("Request log not found for consent id"); + } HIPNotifyRequest hipNotifyRequest = - (HIPNotifyRequest) - requestLogV3Service - .findByConsentId( - hipHealthInformationRequest.getHiRequest().getConsent().getId(), - GatewayConstants.HIP, - headers.getFirst(GatewayConstants.X_HIP_ID)) - .getRequestDetails() - .get(FieldIdentifiers.HIP_NOTIFY_REQUEST); + (HIPNotifyRequest) existingLog.getRequestDetails().get(FieldIdentifiers.HIP_NOTIFY_REQUEST); String hipId = hipNotifyRequest.getNotification().getConsentDetail().getHip().getId(); - if (existingLog == null) { + if (existingConsentLog == null) { throw new IllegalDataStateException("consent id not found in db"); } HealthInformationBundleRequest healthInformationBundleRequest = HealthInformationBundleRequest.builder() .hipId(hipId) - .careContextsWithPatientReferences(existingLog.getCareContexts()) + .careContextsWithPatientReferences(existingConsentLog.getCareContexts()) .build(); + requestLogV3Service.updateConsentStatus( + existingConsentLog.getConsentId(), null, RequestStatus.FETCHING_BUNDLE); log.debug( "Health information bundle request HIP : " + healthInformationBundleRequest.toString()); return hipClient.healthInformationBundleRequest(healthInformationBundleRequest).getBody(); @@ -298,6 +315,9 @@ private List fetchHealthInformationPushRequest( EncryptionResponse encryptedData = encryptionService.encrypt(hipHealthInformationRequest, healthInformationBundleResponse); + requestLogV3Service.updateConsentStatus( + hipNotifyRequest.getNotification().getConsentId(), null, RequestStatus.ENCRYPTION_SUCCESS); + HealthInformationDhPublicKey receiverDhPublicKey = hipHealthInformationRequest.getHiRequest().getKeyMaterial().getDhPublicKey(); @@ -362,7 +382,8 @@ private void healthInformationPushNotify( HIPHealthInformationRequest hipHealthInformationRequest, String consentId, List> pushHealthInformationResponse, - HttpHeaders headers) { + HttpHeaders headers) + throws IllegalDataStateException { boolean allSuccess = pushHealthInformationResponse.stream() .allMatch(response -> response.getStatusCode().is2xxSuccessful()); @@ -370,13 +391,14 @@ private void healthInformationPushNotify( String healthInformationStatus = allSuccess ? "DELIVERED" : "ERRORED"; String sessionStatus = allSuccess ? "TRANSFERRED" : "FAILED"; + RequestLog existingLog = + requestLogV3Service.findByConsentId( + consentId, GatewayConstants.HIP, headers.getFirst(GatewayConstants.X_HIP_ID)); + if (existingLog == null) { + throw new IllegalDataStateException("Request log not found for consent id: " + consentId); + } HIPNotifyRequest hipNotifyRequest = - (HIPNotifyRequest) - requestLogV3Service - .findByConsentId( - consentId, GatewayConstants.HIP, headers.getFirst(GatewayConstants.X_HIP_ID)) - .getRequestDetails() - .get(FieldIdentifiers.HIP_NOTIFY_REQUEST); + (HIPNotifyRequest) existingLog.getRequestDetails().get(FieldIdentifiers.HIP_NOTIFY_REQUEST); List listOfCareContexts = hipNotifyRequest.getNotification().getConsentDetail().getCareContexts(); List healthInformationStatusResponseList = new ArrayList<>(); @@ -415,6 +437,12 @@ private void healthInformationPushNotify( .notification(healthInformationNotificationStatus) .build(); log.info(healthInformationPushNotification.toString()); + if (allSuccess) { + requestLogV3Service.updateConsentStatus(consentId, null, RequestStatus.DATA_TRANSFER_SUCCESS); + } else { + requestLogV3Service.updateConsentStatus(consentId, null, RequestStatus.DATA_TRANSFER_ERROR); + log.error("Data transfer failed for consent id: " + consentId); + } try { ResponseEntity response = requestV3Manager.fetchResponseFromGateway( diff --git a/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/link/hipInitiated/HIPLinkV3Service.java b/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/link/hipInitiated/HIPLinkV3Service.java index 1c7ecc85..66a7eb49 100644 --- a/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/link/hipInitiated/HIPLinkV3Service.java +++ b/src/main/java/in/nha/abdm/wrapper/v3/hip/hrp/link/hipInitiated/HIPLinkV3Service.java @@ -99,7 +99,7 @@ public FacadeV3Response addCareContexts(LinkRecordsV3Request linkRecordsV3Reques linkRecordsV3Request.getRequesterId(), linkRecordsV3Request.getCareContexts()); - if (sameCareContexts != null && !sameCareContexts.isEmpty()) { + if (Objects.nonNull(sameCareContexts) && !sameCareContexts.isEmpty()) { return hipContextNotify(linkRecordsV3Request, patient, sameCareContexts); } @@ -351,25 +351,24 @@ public void handleAddCareContexts( RequestStatus.LINK_TOKEN_REQUEST_ERROR); return; } + linkTokenService.saveLinkToken( onGenerateTokenResponse.getAbhaAddress(), onGenerateTokenResponse.getLinkToken(), Objects.requireNonNull(headers.getFirst(GatewayConstants.X_HIP_ID))); // Fetching the GenerateLinkToken request - RequestLog requestLog = + RequestLog RequestLog = requestLogV3Service.getLogsByAbhaAddress( onGenerateTokenResponse.getAbhaAddress(), Objects.requireNonNull(headers.get(GatewayConstants.X_HIP_ID)).toString()); - if (Objects.isNull(requestLog)) { - log.error("Request log not found for on-linkToken generation to initiate linking"); + if (Objects.isNull(RequestLog)) { return; } - log.info("RequestLog: " + requestLog); LinkRecordsV3Request linkRecordsV3Request = (LinkRecordsV3Request) - requestLog.getRequestDetails().get(FieldIdentifiers.LINK_RECORDS_REQUEST); - log.info("Initiating careContext Linking"); + RequestLog.getRequestDetails().get(FieldIdentifiers.LINK_RECORDS_REQUEST); + FacadeV3Response facadeV3Response = addCareContexts(linkRecordsV3Request); } catch (WebClientResponseException.BadRequest ex) { Object error = BadRequestHandler.getError(ex); @@ -412,7 +411,7 @@ public FacadeV3Response hipContextNotify( .hip(ConsentHIP.builder().id(linkRecordsV3Request.getRequesterId()).build()) .hiTypes(Collections.singletonList(careContext.getHiType())) .date(Utils.getCurrentTimeStamp()) - .careContext( + .careContexts( ConsentCareContexts.builder() .careContextReference(careContext.getReferenceNumber()) .patientReference(patient.getPatientReference())