package com.billpaymentservice.bbps.util; import java.security.SecureRandom; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import com.billpaymentservice.bbps.dto.AdditionalInfoBillDTO; import com.billpaymentservice.bbps.dto.CustomerParamDAO; import com.billpaymentservice.bbps.dto.ResponseModel; import com.billpaymentservice.bbps.dto.request.BillFetchByBillIdRequest; import com.billpaymentservice.bbps.dto.request.BillPaymentRequest; 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.FetchBillValidateResponse; import com.billpaymentservice.bbps.dto.sentRequest.BillPaymentForwardRequest; import com.billpaymentservice.bbps.dto.sentRequest.FetchBillForwardRequest; import com.billpaymentservice.bbps.dto.sentRequest.FetchBillValidatestForwardRequest; import com.billpaymentservice.bbps.entites.AdditionalInfoBill; import com.billpaymentservice.bbps.entites.AdditionalInfoBillValidate; import com.billpaymentservice.bbps.entites.BBPSMastersData; import com.billpaymentservice.bbps.entites.BillMaster; import com.billpaymentservice.bbps.entites.BillValidation; import com.billpaymentservice.bbps.entites.BillerDetails; import com.billpaymentservice.bbps.entites.BillerResponse; import com.billpaymentservice.bbps.entites.CustomerParamBill; import com.billpaymentservice.bbps.entites.CustomerParamBillValidation; import com.billpaymentservice.bbps.entites.InboundTraceLog; import com.billpaymentservice.bbps.entites.OutboundTraceLog; import com.billpaymentservice.bbps.entites.PaymentChannel; import com.billpaymentservice.bbps.entites.PaymentMode; import com.billpaymentservice.bbps.entites.BharatConnectMaster; import com.billpaymentservice.bbps.exception.CustomException; import com.billpaymentservice.bbps.repository.BBPSMasterDataRepo; import com.billpaymentservice.bbps.repository.BillMasterRepository; import com.billpaymentservice.bbps.repository.BillValidationRepository; import com.billpaymentservice.bbps.repository.BillerDataRepository; import com.billpaymentservice.bbps.repository.InboundTraceLogRepository; import com.billpaymentservice.bbps.repository.OutboundTraceLogRepository; import com.fasterxml.jackson.databind.ObjectMapper; @Component public class Helper { private static final Logger LOGGER = LoggerFactory.getLogger(Helper.class); private final InboundTraceLogRepository inboundTraceLogRepository; private final OutboundTraceLogRepository outboundTraceLogRepository; private static final String CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private static final SecureRandom secureRandom = new SecureRandom(); private final ObjectMapper objectMapper = new ObjectMapper(); private final BBPSMasterDataRepo bbpsMasterDataRepo; // Constructor Injection public Helper(BBPSMasterDataRepo bbpsMasterDataRepo, InboundTraceLogRepository inboundTraceLogRepository, OutboundTraceLogRepository outboundTraceLogRepository,BillerDataRepository billerDataRepository, BillMasterRepository billMasterRepository,BillValidationRepository billValidationRepository) { this.inboundTraceLogRepository = inboundTraceLogRepository; this.outboundTraceLogRepository = outboundTraceLogRepository; this.bbpsMasterDataRepo = bbpsMasterDataRepo;} /** * Validates whether the merchant exists and is active. * * @param requestModel MerchantRequestModel containing merchant details * @return true if merchant exists and is active * @throws CustomException if merchant is invalid or inactive * * * */ public void startPolling(T requestObject, // Request object (any type) Function apiCallFunction, // Function to call API int intervalSeconds, // gap between two polls int maxDurationSeconds // total polling time ) { new Thread(() -> { try { int maxAttempts = maxDurationSeconds / intervalSeconds; for (int i = 0; i < maxAttempts; i++) { LOGGER.info("⏳ Polling attempt {}...", i + 1); ResponseModel response = apiCallFunction.apply(requestObject); LOGGER.info("📥 Poll response: {}", response); if ("SUCCESS".equalsIgnoreCase(response.getStatus())) { LOGGER.info("✅ Polling successful, stopping early."); break; } Thread.sleep(intervalSeconds * 1000L); } } catch (Exception e) { LOGGER.error("❌ Error in polling thread: {}", e.getMessage(), e); } }).start(); } public void validateMerchant(String mid) { if (mid == null || mid == "") { LOGGER.warn("MerchantRequestModel or MID is null"); throw new CustomException("Mid is required", "FAILED", BBPSConstant.BADREQUEST, null); } BBPSMastersData merchantValidation = bbpsMasterDataRepo.findByMid(mid); if (merchantValidation == null) { LOGGER.warn("Merchant not found for MID: {}", mid); throw new CustomException("Merchant not found by id", "FAILED", BBPSConstant.BADREQUEST, null); } if (merchantValidation.getApiKey() == null && merchantValidation.getSecreteKey() == null) { LOGGER.warn("Merchant BBPS service is not active MID: {}", mid); throw new CustomException("Merchant BBPS Service is not active by mid", "FAILED", BBPSConstant.BADREQUEST, null); } if (!Boolean.TRUE.equals(merchantValidation.getIsActive())) { LOGGER.warn("Merchant inactive for MID: {}", mid); throw new CustomException("Merchant is inactive", "FAILED", BBPSConstant.BADREQUEST, null); } LOGGER.info("Merchant is valid and active for MID: {}", mid); // Agar exception nahi throw hua, merchant valid hai } public static String generateTxnId(int n) { StringBuilder sb = new StringBuilder(n); for (int i = 0; i < n; i++) { int index = secureRandom.nextInt(CHARACTERS.length()); sb.append(CHARACTERS.charAt(index)); } return sb.toString(); // Prefix } public String convertObjectToJson(Object obj) { if (obj == null) return "null"; try { return new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(obj); } catch (com.fasterxml.jackson.core.JsonProcessingException e) { // log appropriately (use your existing logger) System.err.println("JSON conversion failed: " + e.getMessage()); return "{}"; // or "N/A" depending on your needs } } /* ---------- Trace helper methods ---------- */ public InboundTraceLog createInboundLog(String requestId, String txnId, String apiName, String mid, String httpMethod, String requestPayload) { if(inboundTraceLogRepository.findByRequestId(requestId) != null) { throw new CustomException("Duplicate Request ID: " + requestId); } InboundTraceLog inboundLog = new InboundTraceLog(requestId, txnId, apiName, mid == null ? "N/A" : mid, "BBPS_ORG", httpMethod, requestPayload == null ? "N/A" : requestPayload); inboundTraceLogRepository.save(inboundLog); return inboundLog; } public void updateInboundLogSuccess(InboundTraceLog inboundLog, String responsePayload, String responseCode) { if (inboundLog == null) return; inboundLog.setResponsePayload(responsePayload); inboundLog.setResponseCode(responseCode); inboundLog.setStatus("SUCCESS"); inboundLog.setResponseTime(LocalDateTime.now()); inboundTraceLogRepository.save(inboundLog); } public void updateInboundLogFailure(InboundTraceLog inboundLog, String responsePayload, String responseCode) { if (inboundLog == null) return; inboundLog.setResponsePayload(responsePayload); inboundLog.setResponseCode(responseCode); inboundLog.setStatus("FAILED"); inboundLog.setResponseTime(LocalDateTime.now()); inboundTraceLogRepository.save(inboundLog); } public OutboundTraceLog createOutboundLog(String txnId, String requestId, String apiName, String url, String httpMethod, String requestPayload) { OutboundTraceLog outboundLog = new OutboundTraceLog(txnId, requestId, apiName, url, httpMethod, requestPayload == null ? "N/A" : requestPayload); outboundTraceLogRepository.save(outboundLog); return outboundLog; } public void updateOutboundLogResponse(OutboundTraceLog outboundLog, String responsePayload) { if (outboundLog == null) return; outboundLog.setResponsePayload(responsePayload); outboundLog.setResponseReceiveTime(LocalDateTime.now()); outboundTraceLogRepository.save(outboundLog); } /* ---------- End helpers ---------- */ // New reusable header builder for BBPS calls public HttpHeaders buildHeaders(BharatConnectMaster headersData) { HttpHeaders headers = new HttpHeaders(); if (headersData != null) { headers.set("x-digiledge-key", headersData.getXDigiledgeKey()); headers.set("agentId", headersData.getAgentId()); headers.set("tenantId", headersData.getTenantId()); } headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }