package com.billpaymentservice.bbps.serviceImpl; import java.util.Map; import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; import com.billpaymentservice.bbps.dto.GeneralResp; import com.billpaymentservice.bbps.dto.ResponseModel; import com.billpaymentservice.bbps.dto.request.BillFetchByBillIdRequest; import com.billpaymentservice.bbps.dto.request.BillFetchByClientIdRequest; import com.billpaymentservice.bbps.dto.request.BillValidateByClientIdRequest; import com.billpaymentservice.bbps.dto.request.FetchBillRequest; import com.billpaymentservice.bbps.dto.request.FetchBillValidatestRequest; import com.billpaymentservice.bbps.dto.response.BillDataResponse; import com.billpaymentservice.bbps.dto.response.FetchBillResponse; import com.billpaymentservice.bbps.dto.response.FetchBillValidateResponse; import com.billpaymentservice.bbps.dto.sentRequest.FetchBillForwardRequest; import com.billpaymentservice.bbps.dto.sentRequest.FetchBillValidatestForwardRequest; import com.billpaymentservice.bbps.entites.BillInitiate; import com.billpaymentservice.bbps.entites.BillMaster; import com.billpaymentservice.bbps.entites.InboundTraceLog; import com.billpaymentservice.bbps.entites.OutboundTraceLog; import com.billpaymentservice.bbps.exception.CustomException; import com.billpaymentservice.bbps.repository.BharatConnectMasterRepository; import com.billpaymentservice.bbps.repository.BillInitateRepository; import com.billpaymentservice.bbps.repository.BillMasterRepository; import com.billpaymentservice.bbps.repository.InboundTraceLogRepository; import com.billpaymentservice.bbps.repository.OutboundTraceLogRepository; import com.billpaymentservice.bbps.service.AgentService; import com.billpaymentservice.bbps.util.BBPSConstant; import com.billpaymentservice.bbps.util.BillerMapperHelper; import com.billpaymentservice.bbps.util.Helper; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @Service public class AgentServiceImpl implements AgentService { @Value("${agent.data.url}") private String agentDtaUrl; private final RestClient restClient; private final HttpService httpService; private final Helper helper; private final BharatConnectMasterRepository beneficiaryDetailsRepository; private final BillerMapperHelper mapperHelper; private final BillMasterRepository billMasterRepository; private final BillInitateRepository billIntiateRepository; private static final Logger LOGGER = LoggerFactory.getLogger(AgentServiceImpl.class); // Reusable ObjectMapper instance private final ObjectMapper objectMapper = new ObjectMapper() .setSerializationInclusion(JsonInclude.Include.NON_NULL); public AgentServiceImpl(RestClient restClient, HttpService httpService, Helper helper, BharatConnectMasterRepository beneficiaryDetailsRepository, InboundTraceLogRepository inboundTraceLogRepository, OutboundTraceLogRepository outboundTraceLogRepository, BillMasterRepository billMasterRepository, BillInitateRepository billIntiateRepository, BillerMapperHelper mapperHelper) { this.restClient = restClient; this.httpService = httpService; this.helper = helper; this.beneficiaryDetailsRepository = beneficiaryDetailsRepository; this.billMasterRepository = billMasterRepository; this.billIntiateRepository = billIntiateRepository; this.mapperHelper = mapperHelper; } @Override public ResponseModel initiateBillFetch(FetchBillRequest fetchBillRequest) { String apiName = BBPSConstant.API_INITIATE_BILL_FETCH; String requestId = fetchBillRequest.getReqId(); String mid = fetchBillRequest.getMid(); LOGGER.info("[{}] START | reqId={} | mid={} | billerId={}", apiName, requestId, mid, fetchBillRequest.getBillerId()); String txnId = helper.generateTxnId(15); String fullUrl = agentDtaUrl + BBPSConstant.BILL_FETCH_INTI; fetchBillRequest.setClientReqId(txnId); FetchBillForwardRequest forwardReq = mapperHelper.fetchBillForwardRequestMap(fetchBillRequest); String forwardJson = helper.convertObjectToJson(forwardReq); String requestJson = helper.convertObjectToJson(fetchBillRequest); InboundTraceLog inboundLog = helper.createInboundLog(requestId, txnId, apiName, fetchBillRequest.getMid(), BBPSConstant.HTTP_POST, requestJson); helper.validateMerchant(mid); OutboundTraceLog outboundLog = helper.createOutboundLog(txnId, requestId, apiName, fullUrl, BBPSConstant.HTTP_POST, forwardJson); LOGGER.debug("Outbound log created successfully for txnId: {} and reqId: {}", txnId, requestId); try { LOGGER.info("[{}] Calling external API | URL={}", apiName, fullUrl); Map responseMap = httpService.postRequest(fullUrl, forwardJson, helper.buildHeaders(beneficiaryDetailsRepository.findByOrgId(BBPSConstant.ORG_ID))); String responseData = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY); helper.updateOutboundLogResponse(outboundLog, responseData); LOGGER.debug("Response received from BBPS: {}", responseData); Map dataMap = objectMapper.readValue(responseData, new TypeReference>() { }); if (!dataMap.containsKey(BBPSConstant.RESPONSE_GENERIC_KEY)) { helper.updateInboundLogFailure(inboundLog, responseData, BBPSConstant.INVALID_RESPONSE); LOGGER.warn("Invalid response received for txnId: {}", txnId); throw new CustomException(String.valueOf(dataMap.get("message")), String.valueOf(dataMap.get("status")), Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), String.valueOf(dataMap.get("remarks"))); } BillMaster billMaster = new BillMaster(); billMaster.setBillId((String) dataMap.get("billId")); billMaster.setReqId(fetchBillRequest.getReqId()); billMaster.setTxnId(txnId); billMaster.setClientUserId(fetchBillRequest.getClientUserId()); billMasterRepository.save(billMaster); LOGGER.info("BillMaster saved for billId: {}", billMaster.getBillId()); FetchBillResponse fetchBillResponse = objectMapper.convertValue(dataMap, FetchBillResponse.class); GeneralResp generalResponse = fetchBillResponse.getGenericResponse(); helper.updateInboundLogSuccess(inboundLog, responseData, generalResponse.getStatus()); BillInitiate billInitiate = new BillInitiate(); billInitiate.setBillId((String) dataMap.get("billId")); billInitiate.setReqId(fetchBillRequest.getReqId()); billInitiate.setTxnId(txnId); billInitiate.setClientUserId(fetchBillRequest.getClientUserId()); billIntiateRepository.save(billInitiate); LOGGER.info("BillInitiate entry saved for billId: {}", billInitiate.getBillId()); BillFetchByBillIdRequest billFetchByBillIdRequest = new BillFetchByBillIdRequest(); billFetchByBillIdRequest.setBillId(fetchBillResponse.getBillId()); billFetchByBillIdRequest.setMid(fetchBillRequest.getMid()); billFetchByBillIdRequest.setReqId(requestId); LOGGER.info("Waiting for 2 seconds before fetching bill by ID..."); try { Thread.sleep((long) BBPSConstant.BILL_FETCH_DELAY_MS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOGGER.warn("Thread interrupted during delay: {}", e.getMessage()); } LOGGER.info("Calling internal method Fetching bill by ID: {}", billFetchByBillIdRequest.getBillId()); LOGGER.info("[{}] END | reqId={} | status={}", apiName, requestId, generalResponse.getStatus()); return fetchBillById(billFetchByBillIdRequest, inboundLog); } catch (JsonProcessingException e) { LOGGER.error("JSON Parsing Error: {}", e.getMessage(), e); helper.updateInboundLogFailure(inboundLog, e.getMessage(), BBPSConstant.JSON_ERROR); // Use standardized user-facing message and status, keep internal details in remarks throw new CustomException(BBPSConstant.MSG_INVALID_JSON_FROM_UPSTREAM, BBPSConstant.FAILED_STATUS, BBPSConstant.INVALID_JSON_STATUS_CODE, e.getMessage()); } } public ResponseModel fetchBillById(BillFetchByBillIdRequest billFetchByBillIdRequest, InboundTraceLog inboundLog) { LOGGER.info("Fetching bill by BILLID for request ID={} and MID={}", billFetchByBillIdRequest.getReqId(), billFetchByBillIdRequest.getMid()); String apiName = BBPSConstant.API_FETCH_BILL_BY_ID; String txnId = helper.generateTxnId(15); String reqId = billFetchByBillIdRequest.getReqId(); String billId = billFetchByBillIdRequest.getBillId(); String userId = billFetchByBillIdRequest.getClientUserId(); String fullUrl = agentDtaUrl + BBPSConstant.BILL_FETCH_BY_ID + billFetchByBillIdRequest.getBillId(); OutboundTraceLog outboundLog = helper.createOutboundLog(txnId, reqId, apiName, fullUrl, BBPSConstant.HTTP_GET, null); LOGGER.debug("Outbound log created successfully for FetchBillById: {}", fullUrl); try { LOGGER.info("Calling external API: {}", fullUrl); Map responseMap = httpService.getRequest(fullUrl, helper.buildHeaders(beneficiaryDetailsRepository.findByOrgId(BBPSConstant.ORG_ID))); String responseData = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY); LOGGER.info("Bill FetchById Response: {}", responseData); helper.updateOutboundLogResponse(outboundLog, responseData); Map dataMap = objectMapper.readValue(responseData, new TypeReference>() { }); if (!dataMap.containsKey(BBPSConstant.RESPONSE_GENERIC_KEY)) { helper.updateInboundLogFailure(inboundLog, responseData, BBPSConstant.INVALID_RESPONSE); LOGGER.warn("Invalid response structure for txnId: {}", txnId); throw new CustomException(String.valueOf(dataMap.get("message")), String.valueOf(dataMap.get("status")), Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), String.valueOf(dataMap.get("remarks"))); } BillDataResponse responseWrapper = objectMapper.convertValue(dataMap, BillDataResponse.class); GeneralResp generalResp = responseWrapper.getGenericResponse(); String status = generalResp.getStatus(); LOGGER.info("Current Bill Status: {}", status); helper.updateInboundLogSuccess(inboundLog, responseData, generalResp.getStatus()); mapperHelper.saveOrUpdateBillData(responseWrapper, billFetchByBillIdRequest, txnId, reqId, userId); LOGGER.info("Bill data saved successfully for billId: {}", billId); return new ResponseModel(generalResp.getMessage(), generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), responseWrapper); } catch (JsonProcessingException e) { LOGGER.error("Error parsing BillById JSON: {}", e.getMessage(), e); helper.updateInboundLogFailure(inboundLog, e.getMessage(), BBPSConstant.JSON_ERROR); throw new CustomException(BBPSConstant.MSG_INVALID_JSON_FROM_UPSTREAM, BBPSConstant.FAILED_STATUS, BBPSConstant.INVALID_JSON_STATUS_CODE, e.getMessage()); } } @Override public ResponseModel fetchBillById(BillFetchByBillIdRequest billFetchByBillIdRequest) { String apiName = BBPSConstant.API_FETCH_BILL_BY_ID; String reqId = billFetchByBillIdRequest.getReqId(); String billId = billFetchByBillIdRequest.getBillId(); String mid = billFetchByBillIdRequest.getMid(); String userId = billFetchByBillIdRequest.getClientUserId(); String requestJson = helper.convertObjectToJson(billFetchByBillIdRequest); LOGGER.info("[{}] START | reqId={} | mid={} | billId={} | userId={}", apiName, reqId, mid, billId, userId); String fullUrl = agentDtaUrl + BBPSConstant.BILL_FETCH_BY_ID + billFetchByBillIdRequest.getBillId(); String txnId = helper.generateTxnId(15); InboundTraceLog inboundLog = helper.createInboundLog(reqId, txnId, apiName, billFetchByBillIdRequest.getMid(), BBPSConstant.HTTP_GET, requestJson); LOGGER.info("Initiating {} API for billId={} and reqId={}", apiName, billId, reqId); OutboundTraceLog outboundLog = helper.createOutboundLog(txnId, reqId, apiName, fullUrl, BBPSConstant.HTTP_GET, null); try { LOGGER.info("Calling external BBPS API for FetchBillById, URL={}", fullUrl); Map responseMap = httpService.getRequest(fullUrl, helper.buildHeaders(beneficiaryDetailsRepository.findByOrgId(BBPSConstant.ORG_ID))); String responseData = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY); LOGGER.info("Response received from BBPS for billId={} : {}", billId, responseData); helper.updateOutboundLogResponse(outboundLog, responseData); Map dataMap = objectMapper.readValue(responseData, new TypeReference>() { }); if (!dataMap.containsKey(BBPSConstant.RESPONSE_GENERIC_KEY)) { helper.updateInboundLogFailure(inboundLog, responseData, BBPSConstant.INVALID_RESPONSE); LOGGER.warn("Invalid response structure received for billId={} | Response={}", billId, responseData); throw new CustomException(String.valueOf(dataMap.get("message")), String.valueOf(dataMap.get("status")), Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), String.valueOf(dataMap.get("remarks"))); } BillDataResponse responseWrapper = objectMapper.convertValue(dataMap, BillDataResponse.class); GeneralResp generalResp = responseWrapper.getGenericResponse(); ResponseModel responseModel = new ResponseModel(generalResp.getMessage(), generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), responseWrapper); // update inbound log success and persist bill data helper.updateInboundLogSuccess(inboundLog, responseData, generalResp.getStatus()); mapperHelper.saveOrUpdateBillData(responseWrapper, billFetchByBillIdRequest, txnId, reqId, userId); LOGGER.info("Bill data saved successfully for billId={} | Status={}", billId, generalResp.getStatus()); LOGGER.info("[{}] END | reqId={} | status={}", apiName, reqId, generalResp.getStatus()); return responseModel; } catch (JsonProcessingException e) { LOGGER.error("Error parsing responseData JSON for billId={} : {}", billId, e.getMessage(), e); helper.updateInboundLogFailure(inboundLog, e.getMessage(), BBPSConstant.JSON_ERROR); throw new CustomException(BBPSConstant.MSG_INVALID_JSON_FROM_UPSTREAM, BBPSConstant.FAILED_STATUS, BBPSConstant.INVALID_JSON_STATUS_CODE, e.getMessage()); } } @Override public ResponseModel initiateBillValidate(FetchBillValidatestRequest fetchBillValidateRequest) { String apiName = BBPSConstant.API_INITIATE_BILL_VALIDATE; String reqId = fetchBillValidateRequest.getReqId(); String mid = fetchBillValidateRequest.getMid(); LOGGER.info("[{}] START | reqId={} | mid={} | billerId={}", apiName, fetchBillValidateRequest.getReqId(), mid, fetchBillValidateRequest.getBillerId()); String txnId = helper.generateTxnId(15); String fullUrl = agentDtaUrl + BBPSConstant.BILLER_VALIDATE_URL; fetchBillValidateRequest.setClientReqId(txnId); FetchBillValidatestForwardRequest forwardReq = mapperHelper .fetchBillValidatestForwardRequest(fetchBillValidateRequest); String forwardJson = helper.convertObjectToJson(forwardReq); String requestJson = helper.convertObjectToJson(fetchBillValidateRequest); InboundTraceLog inboundLog = helper.createInboundLog(reqId, txnId, apiName, fetchBillValidateRequest.getMid(), BBPSConstant.HTTP_POST, requestJson); helper.validateMerchant(fetchBillValidateRequest.getMid()); OutboundTraceLog outboundLog = helper.createOutboundLog(txnId, reqId, apiName, fullUrl, BBPSConstant.HTTP_POST, forwardJson); LOGGER.debug("Outbound log created successfully for txnId: {} and reqId: {}", txnId, reqId); try { LOGGER.info("[{}] Calling external API | URL={}", apiName, fullUrl); Map responseMap = httpService.postRequest(fullUrl, forwardJson, helper.buildHeaders(beneficiaryDetailsRepository.findByOrgId(BBPSConstant.ORG_ID))); String responseData = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY); helper.updateOutboundLogResponse(outboundLog, responseData); LOGGER.debug("Response received from BBPS: {}", responseData); Map dataMap = objectMapper.readValue(responseData, new TypeReference>() { }); if (!dataMap.containsKey(BBPSConstant.RESPONSE_GENERIC_KEY)) { helper.updateInboundLogFailure(inboundLog, responseData, BBPSConstant.INVALID_RESPONSE); LOGGER.warn("Invalid response received for txnId: {}", txnId); throw new CustomException(String.valueOf(dataMap.get("message")), String.valueOf(dataMap.get("status")), Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), String.valueOf(dataMap.get("remarks"))); } BillMaster billMaster = new BillMaster(); billMaster.setBillId((String) dataMap.get("billId")); billMaster.setReqId(fetchBillValidateRequest.getReqId()); billMaster.setTxnId(txnId); billMasterRepository.save(billMaster); LOGGER.info("BillMaster saved for billId: {}", billMaster.getBillId()); FetchBillResponse fetchBillResponse = objectMapper.convertValue(dataMap, FetchBillResponse.class); GeneralResp generalResponse = fetchBillResponse.getGenericResponse(); helper.updateInboundLogSuccess(inboundLog, responseData, generalResponse.getStatus()); BillInitiate billInitiate = new BillInitiate(); billInitiate.setBillId((String) dataMap.get("billId")); billInitiate.setReqId(fetchBillValidateRequest.getReqId()); billInitiate.setTxnId(txnId); billIntiateRepository.save(billInitiate); LOGGER.info("BillInitiate entry saved for billId: {}", billInitiate.getBillId()); BillFetchByBillIdRequest billFetchByBillIdRequest = new BillFetchByBillIdRequest(); billFetchByBillIdRequest.setBillId(fetchBillResponse.getBillId()); billFetchByBillIdRequest.setMid(fetchBillValidateRequest.getMid()); billFetchByBillIdRequest.setReqId(reqId); LOGGER.info("Waiting for 2 seconds before fetching bill by ID..."); try { Thread.sleep((long) BBPSConstant.BILL_VALIDATE_DELAY_MS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOGGER.warn("Thread interrupted during delay: {}", e.getMessage()); } LOGGER.info("Calling internal method Fetching bill by ID: {}", billFetchByBillIdRequest.getBillId()); LOGGER.info("[{}] END | reqId={} | status={}", apiName, reqId, generalResponse.getStatus()); return BillvaidateByBillId(billFetchByBillIdRequest, inboundLog); } catch (JsonProcessingException e) { LOGGER.error("JSON Parsing Error: {}", e.getMessage(), e); helper.updateInboundLogFailure(inboundLog, e.getMessage(), BBPSConstant.JSON_ERROR); throw new CustomException(BBPSConstant.MSG_INVALID_JSON_FROM_UPSTREAM, BBPSConstant.FAILED_STATUS ,BBPSConstant.INVALID_JSON_STATUS_CODE, e.getMessage()); } } public ResponseModel BillvaidateByBillId(BillFetchByBillIdRequest billRequest, InboundTraceLog inboundLog) { { LOGGER.info("Validating bill by BILLID for request ID={} and MID={}", billRequest.getReqId(), billRequest.getMid()); String apiName = BBPSConstant.API_FETCH_BILL_BY_ID; String txnId = helper.generateTxnId(15); String reqId = billRequest.getReqId(); String billId = billRequest.getBillId(); String fullUrl = agentDtaUrl + BBPSConstant.BILL_VALIDATE_ID_URL + billRequest.getBillId(); OutboundTraceLog outboundLog = helper.createOutboundLog(txnId, reqId, apiName, fullUrl, BBPSConstant.HTTP_GET, null); LOGGER.debug("Outbound log created successfully for FetchBillById: {}", fullUrl); try { LOGGER.info("Calling external API: {}", fullUrl); Map responseMap = httpService.getRequest(fullUrl, helper.buildHeaders(beneficiaryDetailsRepository.findByOrgId(BBPSConstant.ORG_ID))); String responseData = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY); LOGGER.info("Bill FetchById Response: {}", responseData); helper.updateOutboundLogResponse(outboundLog, responseData); Map dataMap = objectMapper.readValue(responseData, new TypeReference>() { }); if (!dataMap.containsKey(BBPSConstant.RESPONSE_GENERIC_KEY)) { helper.updateInboundLogFailure(inboundLog, responseData, BBPSConstant.INVALID_RESPONSE); LOGGER.warn("Invalid response structure for txnId: {}", txnId); throw new CustomException(String.valueOf(dataMap.get("message")), String.valueOf(dataMap.get("status")), Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), String.valueOf(dataMap.get("remarks"))); } FetchBillValidateResponse responseWrapper = objectMapper.convertValue(dataMap, FetchBillValidateResponse.class); GeneralResp generalResp = responseWrapper.getGenericResponse(); String status = generalResp.getStatus(); LOGGER.info("Current Bill Status: {}", status); helper.updateInboundLogSuccess(inboundLog, responseData, generalResp.getStatus()); System.out.println("responseWrapper:" + responseWrapper); mapperHelper.saveBillValidation(responseWrapper, billRequest, txnId); return new ResponseModel(generalResp.getMessage(), generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), responseWrapper); } catch (JsonProcessingException e) { LOGGER.error("Error parsing BillById JSON: {}", e.getMessage(), e); helper.updateInboundLogFailure(inboundLog, e.getMessage(), BBPSConstant.JSON_ERROR); throw new CustomException(BBPSConstant.MSG_INVALID_JSON_FROM_UPSTREAM, BBPSConstant.FAILED_STATUS, BBPSConstant.INVALID_JSON_STATUS_CODE, e.getMessage()); } } } @Override public ResponseModel initiateBillValidateByBillId(BillFetchByBillIdRequest billRequest) { String apiName = BBPSConstant.API_FETCH_BILL_BY_ID; String reqId = billRequest.getReqId(); String billId = billRequest.getBillId(); String mid = billRequest.getMid(); String requestJson = helper.convertObjectToJson(billRequest); LOGGER.info("[{}] START | reqId={} | mid={} | billId={}", apiName, billRequest, mid, billId); String txnId = helper.generateTxnId(15); String fullUrl = agentDtaUrl + BBPSConstant.BILL_VALIDATE_ID_URL + billRequest.getBillId(); LOGGER.info("Initiating {} API for billId={} and reqId={}", apiName, billId, reqId); InboundTraceLog inboundLog = helper.createInboundLog(reqId, txnId, apiName, billRequest.getMid(), BBPSConstant.HTTP_GET, requestJson); helper.validateMerchant(billRequest.getMid()); try { OutboundTraceLog outboundLog = helper.createOutboundLog(txnId, reqId, apiName, fullUrl, BBPSConstant.HTTP_GET, null); LOGGER.info("Calling external BBPS API for ValidateByBillId, URL={}", fullUrl); Map responseMap = httpService.getRequest(fullUrl, helper.buildHeaders(beneficiaryDetailsRepository.findByOrgId(BBPSConstant.ORG_ID))); String responseData = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY); LOGGER.info("Response received from BBPS for billId={} : {}", billId, responseData); helper.updateOutboundLogResponse(outboundLog, responseData); Map dataMap = objectMapper.readValue(responseData, new com.fasterxml.jackson.core.type.TypeReference>() { }); if (!dataMap.containsKey(BBPSConstant.RESPONSE_GENERIC_KEY)) { helper.updateInboundLogFailure(inboundLog, responseData, BBPSConstant.INVALID_RESPONSE); LOGGER.warn("Invalid response structure received for billId={} | Response={}", billId, responseData); throw new CustomException(String.valueOf(dataMap.get("message")), String.valueOf(dataMap.get("status")), Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), String.valueOf(dataMap.get("remarks"))); } FetchBillValidateResponse responseWrapper = objectMapper.convertValue(dataMap, FetchBillValidateResponse.class); GeneralResp generalResp = responseWrapper.getGenericResponse(); helper.updateInboundLogSuccess(inboundLog, responseData, generalResp.getStatus()); mapperHelper.saveBillValidation(responseWrapper, billRequest, txnId); LOGGER.info("Bill validation saved successfully for billId: {}", billId); LOGGER.info("[{}] END | reqId={} | status={}", apiName, reqId, generalResp.getStatus()); return new ResponseModel(generalResp.getMessage(), generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), responseWrapper); } catch (com.fasterxml.jackson.core.JsonProcessingException e) { LOGGER.error("Error parsing ValidateByBillId JSON: {}", e.getMessage(), e); helper.updateInboundLogFailure(inboundLog, e.getMessage(), BBPSConstant.JSON_ERROR); throw new CustomException(BBPSConstant.MSG_INVALID_JSON_FROM_UPSTREAM,BBPSConstant.FAILED_STATUS, BBPSConstant.INVALID_JSON_STATUS_CODE, e.getMessage()); } } @Override public ResponseModel fetchBillValidateByClientReqId(BillValidateByClientIdRequest billValidateByClientIdRequest) { String apiName = BBPSConstant.API_FETCH_BILL_VALIDATE_BY_CLIENT_ID; String reqId = billValidateByClientIdRequest.getReqId(); String clientReqId = billValidateByClientIdRequest.getClientReqId(); String mid = billValidateByClientIdRequest.getMid(); String txnId = helper.generateTxnId(15); String requestJson = helper.convertObjectToJson(billValidateByClientIdRequest); LOGGER.info("[{}] START | reqId={} | mid={} | clientReqId={}", apiName, reqId, mid, billValidateByClientIdRequest.getClientReqId()); InboundTraceLog inboundLog = helper.createInboundLog(reqId, txnId, apiName, billValidateByClientIdRequest.getMid(), BBPSConstant.HTTP_GET, requestJson); helper.validateMerchant(billValidateByClientIdRequest.getMid()); Optional billInitiate = billIntiateRepository.findByReqId(clientReqId); if (billInitiate.isEmpty()) { new CustomException( BBPSConstant.NO_BILL_FOUND, // message // status BBPSConstant.FAILED_STATUS, BBPSConstant.HTTP_NOT_FOUND, // statusCode "Bill not found in database for given clientReqId" ); } String fullUrl = agentDtaUrl + BBPSConstant.BILL_VALIDATE_BY_CLIENT_REQ_ID + billInitiate.get().getTxnId(); OutboundTraceLog outboundLog = helper.createOutboundLog(txnId, reqId, apiName, fullUrl, BBPSConstant.HTTP_GET, null); try { LOGGER.info("Calling BBPS API FetchBillValidateByClientReqId, URL={}", fullUrl); Map responseMap = httpService.getRequest(fullUrl, helper.buildHeaders(beneficiaryDetailsRepository.findByOrgId(BBPSConstant.ORG_ID))); String responseData = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY); helper.updateOutboundLogResponse(outboundLog, responseData); Map dataMap = objectMapper.readValue(responseData, new TypeReference>() { }); if (!dataMap.containsKey(BBPSConstant.RESPONSE_GENERIC_KEY)) { helper.updateInboundLogFailure(inboundLog, responseData, BBPSConstant.INVALID_RESPONSE); throw new CustomException(String.valueOf(dataMap.get("message")), String.valueOf(dataMap.get("status")), Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), String.valueOf(dataMap.get("remarks"))); } FetchBillValidateResponse responseWrapper = objectMapper.convertValue(dataMap, FetchBillValidateResponse.class); GeneralResp generalResp = responseWrapper.getGenericResponse(); helper.updateInboundLogSuccess(inboundLog, responseData, generalResp.getStatus()); LOGGER.info("[{}] END | reqId={} | status={}", apiName, reqId, generalResp.getStatus()); return new ResponseModel(generalResp.getMessage(), generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), responseWrapper); } catch (JsonProcessingException e) { helper.updateInboundLogFailure(inboundLog, e.getMessage(), BBPSConstant.JSON_ERROR); throw new CustomException(BBPSConstant.MSG_INVALID_JSON_FROM_UPSTREAM, BBPSConstant.FAILED_STATUS, BBPSConstant.INVALID_JSON_STATUS_CODE, e.getMessage()); } } @Override public ResponseModel fetchBillByClientReqId(BillFetchByClientIdRequest billFetchByClientIdRequest) { String apiName = BBPSConstant.API_FETCH_BILL_BY_CLIENT_ID; String reqId = billFetchByClientIdRequest.getReqId(); String clientReqId = billFetchByClientIdRequest.getClientReqId(); String mid = billFetchByClientIdRequest.getMid(); String requestJson = helper.convertObjectToJson(billFetchByClientIdRequest); LOGGER.info("[{}] START | reqId={} | mid={} | clientReqId={}", apiName, reqId, mid, billFetchByClientIdRequest.getClientReqId()); String txnId = helper.generateTxnId(15); InboundTraceLog inboundLog = helper.createInboundLog(reqId, txnId, apiName, billFetchByClientIdRequest.getMid(), BBPSConstant.HTTP_GET, requestJson); helper.validateMerchant(billFetchByClientIdRequest.getMid()); Optional billInitiate = billIntiateRepository.findByReqId(clientReqId); if (billInitiate.isEmpty()) { throw new CustomException( BBPSConstant.NO_BILL_FOUND, // message // status BBPSConstant.FAILED_STATUS, BBPSConstant.HTTP_NOT_FOUND, // statusCode "Bill not found in database for given clientReqId" ); } String fullUrl = agentDtaUrl + BBPSConstant.BILL_VALIDATE_BY_CLIENT_REQ_ID + billInitiate.get().getTxnId(); OutboundTraceLog outboundLog = helper.createOutboundLog(txnId, reqId, apiName, fullUrl, BBPSConstant.HTTP_GET, null); try { LOGGER.info("[{}] Calling external API | URL={} | reqId={}", apiName, fullUrl, reqId); Map responseMap = httpService.getRequest(fullUrl, helper.buildHeaders(beneficiaryDetailsRepository.findByOrgId(BBPSConstant.ORG_ID))); String responseData = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY); helper.updateOutboundLogResponse(outboundLog, responseData); Map dataMap = objectMapper.readValue(responseData, new TypeReference>() { }); if (!dataMap.containsKey(BBPSConstant.RESPONSE_GENERIC_KEY)) { helper.updateInboundLogFailure(inboundLog, responseData, BBPSConstant.INVALID_RESPONSE); throw new CustomException(String.valueOf(dataMap.get("message")), String.valueOf(dataMap.get("status")), Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), String.valueOf(dataMap.get("remarks"))); } BillDataResponse responseWrapper = objectMapper.convertValue(dataMap, BillDataResponse.class); GeneralResp generalResp = responseWrapper.getGenericResponse(); helper.updateInboundLogSuccess(inboundLog, responseData, generalResp.getStatus()); LOGGER.info("[{}] END | reqId={} | status={}", apiName, reqId, generalResp.getStatus()); return new ResponseModel(generalResp.getMessage(), generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), responseWrapper); } catch (JsonProcessingException e) { helper.updateInboundLogFailure(inboundLog, e.getMessage(), BBPSConstant.JSON_ERROR); throw new CustomException(BBPSConstant.MSG_INVALID_JSON_FROM_UPSTREAM, BBPSConstant.FAILED_STATUS, BBPSConstant.INVALID_JSON_STATUS_CODE, e.getMessage()); } } /* * @Override public ResponseModel * initiateBillValidate(FetchBillValidatestRequest fetchBillValidateRequest) { * * ResponseModel responseModel = new ResponseModel(); try { * * helper.validateMerchant(fetchBillValidateRequest.getMid()); * * BharatConnectMaster headersData = * beneficiaryDetailsRepository.findByOrgId("ORG001"); * * if (headersData == null) { responseModel = new * ResponseModel("Tenant Id Is Null", "Not Found", BBPSConstant.BADREQUEST, * headersData); return responseModel; } * * HttpHeaders headers = new HttpHeaders(); headers.set("x-digiledge-key", * headersData.getXDigiledgeKey()); headers.set("agentId", * headersData.getAgentId()); headers.set("tenantId", * headersData.getTenantId()); * headers.setContentType(MediaType.APPLICATION_JSON); * * ObjectMapper objectMapper = new ObjectMapper(); * objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); String * json = objectMapper.writeValueAsString(fetchBillValidateRequest); String url * = agentDtaUrl + BBPSConstant.BILLER_VALIDATE_URL; * * Map responseMap = httpService.postRequest(url, json, * headers); String responseData = responseMap.get("data"); * * log.info("📦 Bill Fetch API Response: {}", responseData); * * if (responseData == null || responseData.isEmpty()) { throw new * CustomException("Empty response from BBPS server"); } * * // ✅ Convert JSON string → Map Map dataMap = * objectMapper.readValue(responseData, new TypeReference>() * {}); * * // ✅ Validate generalResp if (!dataMap.containsKey("genericResponse")) { * throw new CustomException("Invalid response structure from BBPS"); } * * // ✅ Convert to your custom DTO FetchBillValidatestResponse fetchBillResponse * = objectMapper.convertValue(dataMap, FetchBillValidatestResponse.class); * GeneralResp generalResponse = fetchBillResponse.getGenericResponse(); * * // ✅ Build final ResponseModel responseModel = new ResponseModel( * generalResponse.getMessage(), generalResponse.getStatus(), * Integer.parseInt(generalResponse.getStatusCode()), fetchBillResponse ); * * } catch (CustomException ex) { log.warn("Merchant validation failed: {}", * ex.getMessage()); return ex.getResponseModel(); // Directly return * ResponseModel from exception } catch (Exception e) { * log.error("❌ Exception in initiateBillFetch(): {}", e.getMessage(), e); * responseModel.setStatus("500"); * responseModel.setMessage("Exception occurred"); * responseModel.setData(e.getMessage()); } * * return responseModel; } * * @Override public ResponseModel * initiateBillValidateByBillId(BillFetchByBillIdRequest billRequest) { * * ResponseModel responseModel = new ResponseModel(); try { * helper.validateMerchant(billRequest.getMid()); * * BharatConnectMaster headersData = * beneficiaryDetailsRepository.findByOrgId("ORG001"); * * if (headersData == null) { responseModel = new * ResponseModel("Tenant Id Is Null", "Not Found", BBPSConstant.BADREQUEST, * headersData); return responseModel; } * * HttpHeaders headers = new HttpHeaders(); headers.set("x-digiledge-key", * headersData.getXDigiledgeKey()); headers.set("agentId", * headersData.getAgentId()); headers.set("tenantId", * headersData.getTenantId()); * headers.setContentType(MediaType.APPLICATION_JSON); * * ObjectMapper objectMapper = new ObjectMapper(); * objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); String * json = objectMapper.writeValueAsString(billRequest); String url = agentDtaUrl * + BBPSConstant.BILL_ID_URL + billRequest.getBillId(); * * log.info("Full URL: {}", url); * objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); * * // ✅ Call the API using httpService Map responseMap = * httpService.getRequest(url, headers); String responseData = * responseMap.get("data"); * * log.info("📦 Bill Fetch API Response: {}", responseData); * * if (responseData == null || responseData.isEmpty()) { throw new * CustomException("Empty response from BBPS server"); } * * // ✅ Convert JSON string → Map Map dataMap = * objectMapper.readValue(responseData, new TypeReference>() * {}); * * // ✅ Validate generalResp if (!dataMap.containsKey("genericResponse")) { * throw new CustomException("Invalid response structure from BBPS"); } * * // ✅ Convert to your custom DTO BillDataResponse fetchBillResponse = * objectMapper.convertValue(dataMap, BillDataResponse.class); GeneralResp * generalResponse = fetchBillResponse.getGenericResponse(); * * // ✅ Build final ResponseModel responseModel = new ResponseModel( * generalResponse.getRemarks(), generalResponse.getStatus(), * Integer.parseInt(generalResponse.getStatusCode()), fetchBillResponse ); * * } catch (CustomException ex) { log.warn("Merchant validation failed: {}", * ex.getMessage()); return ex.getResponseModel(); // Directly return * ResponseModel from exception } catch (Exception e) { * log.error("❌ Exception in initiateBillFetch(): {}", e.getMessage(), e); * responseModel.setStatus("500"); * responseModel.setMessage("Exception occurred"); * responseModel.setData(e.getMessage()); } * * return responseModel; } */ /* * POLLING METHOD public ResponseModel fetchBillById(BillFetchByBillIdRequest * billFetchByBillIdRequest, InboundTraceLog inboundLog) { String apiName = * "FetchBillById"; String txnId = helper.generateTxnId(15); String reqId = * billFetchByBillIdRequest.getReqId(); String billId = * billFetchByBillIdRequest.getBillId(); String url = agentDtaUrl + * BBPSConstant.BILL_FETCH_BY_ID + "1ced7566-1add-4e01-9ed6-04cd67ac9684"; * * helper.validateMerchant(billFetchByBillIdRequest.getMid()); * * BharatConnectMaster headersData = * beneficiaryDetailsRepository.findByOrgId("ORG001"); HttpHeaders headers = new * HttpHeaders(); headers.set("x-digiledge-key", * headersData.getXDigiledgeKey()); headers.set("agentId", * headersData.getAgentId()); headers.set("tenantId", * headersData.getTenantId()); * headers.setContentType(MediaType.APPLICATION_JSON); * * ObjectMapper objectMapper = new ObjectMapper(); OutboundTraceLog outboundLog * = helper.createOutboundLog(txnId, reqId, apiName, url, "GET", null); * * // ✅ Loop setup long startTime = System.currentTimeMillis(); long * maxWaitTimeMs = 40000; // 40 seconds long intervalMs = 5000; // 5 seconds * * while (true) { try { Map responseMap = * httpService.getRequest(url, headers); String responseData = * responseMap.get("data"); log.info("📦 Bill FetchById Response: {}", * responseData); * * helper.updateOutboundLogResponse(outboundLog, responseData); * * Map dataMap = objectMapper.readValue(responseData, new * TypeReference>() {}); * * if (!dataMap.containsKey("genericResponse")) { * helper.updateInboundLogFailure(inboundLog, responseData, "INVALID_RESPONSE"); * throw new CustomException( String.valueOf(dataMap.get("message")), * String.valueOf(dataMap.get("status")), * Integer.parseInt(String.valueOf(dataMap.get("statusCode"))), * String.valueOf(dataMap.get("remarks")) ); } * * BillDataResponse responseWrapper = objectMapper.convertValue(dataMap, * BillDataResponse.class); GeneralResp generalResp = * responseWrapper.getGenericResponse(); * * String status = generalResp.getStatus(); * log.info("📡 Current Bill Status: {}", status); // ✅ Check for "INPROGRESS" * or pending state if ("INPROGRESS".equalsIgnoreCase(status)) { if * (System.currentTimeMillis() - startTime > maxWaitTimeMs) { * helper.updateInboundLogFailure(inboundLog, "Timeout after 40 seconds", * "FAILED"); throw new CustomException("Timeout", "FAILED", 408, * "Bill fetch still in progress"); } Thread.sleep(intervalMs); continue; // * retry again } // ✅ Final successful response * helper.updateInboundLogSuccess(inboundLog, responseData, * generalResp.getStatus()); return new ResponseModel( generalResp.getMessage(), * generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), * responseWrapper ); } catch (JsonProcessingException e) { * log.error("Error parsing BillById JSON: {}", e.getMessage()); * helper.updateInboundLogFailure(inboundLog, e.getMessage(), "JSON_ERROR"); * throw new CustomException("Invalid JSON received from API"); } catch * (InterruptedException e) { Thread.currentThread().interrupt(); * helper.updateInboundLogFailure(inboundLog, e.getMessage(), "INTERRUPTED"); * throw new CustomException("Thread interrupted during bill status check"); } } * } */ @Override public ResponseModel processBillFetchCallback(BillDataResponse billDataResponse) { LOGGER.info("Recived Call Back from billDataResponse: {}", billDataResponse); if (billDataResponse.getGenericResponse().getStatusCode().equals(BBPSConstant.SUCCESS_CODE_STR)) { } else { LOGGER.info("Bill Fetch Callback Failed with Status: {}", billDataResponse.getGenericResponse().getStatus()); } return new ResponseModel(BBPSConstant.CALLBACK_RECEIVED_SUCCESS, BBPSConstant.SUCCESS_CODE_STR, BBPSConstant.HTTP_OK_INT, ""); } @Override public ResponseModel processBillValidateCallback(FetchBillValidateResponse billValidateResponse) { LOGGER.info("Recived Call Back from FetchBillValidateResponse: {}", billValidateResponse); if (billValidateResponse.getGenericResponse().getStatusCode().equals(BBPSConstant.SUCCESS_CODE_STR)) { } else { LOGGER.info("Bill Fetch Callback Failed with Status: {}", billValidateResponse.getGenericResponse().getStatus()); } return new ResponseModel(BBPSConstant.CALLBACK_RECEIVED_SUCCESS, BBPSConstant.SUCCESS_CODE_STR, BBPSConstant.HTTP_OK_INT, ""); } }