added intentbased pg
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
package com.billpaymentservice.bbps.serviceImpl;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.billpaymentservice.bbps.dto.PaymentStartReturnDto;
|
||||
import com.billpaymentservice.bbps.dto.ResponseModel;
|
||||
import com.billpaymentservice.bbps.dto.request.PaymentStartUserRequest;
|
||||
import com.billpaymentservice.bbps.dto.response.PaymentStartApiResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.PaymentStatusResponse;
|
||||
import com.billpaymentservice.bbps.dto.sentRequest.PaymentDetailSentRequest;
|
||||
import com.billpaymentservice.bbps.dto.sentRequest.PaymentRequestPayload;
|
||||
import com.billpaymentservice.bbps.entites.InboundTraceLog;
|
||||
import com.billpaymentservice.bbps.exception.CustomException;
|
||||
import com.billpaymentservice.bbps.repository.PaymentStartRecordRepository;
|
||||
import com.billpaymentservice.bbps.repository.BharatConnectMasterRepository;
|
||||
import com.billpaymentservice.bbps.repository.BBPSMasterDataRepo;
|
||||
import com.billpaymentservice.bbps.service.PaymentStartService;
|
||||
import com.billpaymentservice.bbps.util.EncryptionUtil;
|
||||
import com.billpaymentservice.bbps.util.Helper;
|
||||
import com.billpaymentservice.bbps.util.BBPSConstant;
|
||||
import com.billpaymentservice.bbps.util.BillerMapperHelper;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.billpaymentservice.bbps.entites.OutboundTraceLog;
|
||||
import com.billpaymentservice.bbps.entites.BharatConnectMaster;
|
||||
|
||||
@Service
|
||||
public class PaymentStartServiceImpl implements PaymentStartService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PaymentStartServiceImpl.class);
|
||||
|
||||
private String uatPaymentUrl="https://uat.godemo.in/api/UATIntegration/paymentrequest/seamless";
|
||||
|
||||
private final PaymentStartRecordRepository paymentStartRecordRepository;
|
||||
private final HttpService httpService;
|
||||
private final EncryptionUtil encryptionUtil;
|
||||
private final Helper helper;
|
||||
private final BharatConnectMasterRepository bharatConnectMasterRepository;
|
||||
private final BBPSMasterDataRepo bbpsMasterDataRepo;
|
||||
private final BillerMapperHelper bbpsMapperHelper ;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public PaymentStartServiceImpl(PaymentStartRecordRepository paymentStartRecordRepository,
|
||||
HttpService httpService,
|
||||
EncryptionUtil encryptionUtil,
|
||||
Helper helper,
|
||||
BharatConnectMasterRepository bharatConnectMasterRepository,
|
||||
BBPSMasterDataRepo bbpsMasterDataRepo,
|
||||
BillerMapperHelper bbpsMapperHelper) {
|
||||
this.paymentStartRecordRepository = paymentStartRecordRepository;
|
||||
this.httpService = httpService;
|
||||
this.encryptionUtil = encryptionUtil;
|
||||
this.helper = helper;
|
||||
this.bharatConnectMasterRepository = bharatConnectMasterRepository;
|
||||
this.bbpsMasterDataRepo = bbpsMasterDataRepo;
|
||||
this.bbpsMapperHelper = bbpsMapperHelper;
|
||||
}
|
||||
@Override
|
||||
public ResponseModel startPayment(PaymentStartUserRequest request) {
|
||||
|
||||
String requestId = request.getReqId();
|
||||
String apiName = "StartPayment";
|
||||
String txnId = helper.generateTxnId(15);
|
||||
|
||||
helper.validateMerchant(request.getMid());
|
||||
|
||||
// inbound log
|
||||
String requestJson = helper.convertObjectToJson(request);
|
||||
InboundTraceLog inboundLog =
|
||||
helper.createInboundLog(requestId, txnId, apiName, request.getMid(),
|
||||
BBPSConstant.HTTP_POST, requestJson);
|
||||
|
||||
// Prepare request payload
|
||||
PaymentDetailSentRequest sent = createPaymentSentRequest(request);
|
||||
String orderNo = "ORD" + helper.generateTxnId(12);
|
||||
sent.setOrderNo(orderNo);
|
||||
|
||||
String plaintext = helper.convertObjectToJson(sent);
|
||||
String encKey = BBPSConstant.enckey;
|
||||
sent.setEnckey(encKey);
|
||||
|
||||
String encrypted = encryptionUtil.encryptMData(plaintext, encKey);
|
||||
|
||||
PaymentRequestPayload finalPayload = new PaymentRequestPayload();
|
||||
finalPayload.setMid(BBPSConstant.mid);
|
||||
finalPayload.setPayload(encrypted);
|
||||
|
||||
String forwardJson = helper.convertObjectToJson(finalPayload);
|
||||
OutboundTraceLog outboundLog =
|
||||
helper.createOutboundLog(txnId, requestId, apiName, uatPaymentUrl,
|
||||
BBPSConstant.HTTP_POST, forwardJson);
|
||||
|
||||
// --- CALL EXTERNAL API ---
|
||||
Map<String, String> responseMap =
|
||||
httpService.postRequest(uatPaymentUrl, forwardJson, null);
|
||||
|
||||
LOGGER.info("Payment Start Response: " + responseMap);
|
||||
|
||||
int httpCode = Integer.parseInt(responseMap.getOrDefault("respCode", "500"));
|
||||
String respBody = responseMap.get(BBPSConstant.RESPONSE_DATA_KEY);
|
||||
|
||||
helper.updateOutboundLogResponse(outboundLog, respBody);
|
||||
|
||||
// --- HTTP FAILURE ---
|
||||
if (httpCode != 200) {
|
||||
helper.updateInboundLogFailure(inboundLog, respBody, String.valueOf(httpCode));
|
||||
|
||||
throw new CustomException(
|
||||
"Upstream HTTP error",
|
||||
"FAILED",
|
||||
httpCode,
|
||||
respBody
|
||||
);
|
||||
}
|
||||
|
||||
if (respBody == null || respBody.isEmpty()) {
|
||||
helper.updateInboundLogFailure(inboundLog, "Empty response from payment provider", "500");
|
||||
|
||||
throw new CustomException(
|
||||
"Empty response from payment provider",
|
||||
"FAILED",
|
||||
500,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
// --- Convert JSON to object ---
|
||||
PaymentStartApiResponse apiResponse = null;
|
||||
try {
|
||||
Map<String, Object> top = objectMapper.readValue(respBody, new TypeReference<Map<String, Object>>(){});
|
||||
|
||||
// Pick inner payload if present
|
||||
Map<String, Object> payload = top;
|
||||
if (top.containsKey("data") && top.get("data") instanceof Map) {
|
||||
//noinspection unchecked
|
||||
payload = (Map<String, Object>) top.get("data");
|
||||
}
|
||||
|
||||
// Simple failure detection: status == Failure OR statusCode != 200
|
||||
String status = String.valueOf(payload.getOrDefault("status", top.getOrDefault("status", ""))).trim();
|
||||
int outcomeCode = 0;
|
||||
Object scObj = payload.getOrDefault("statusCode", top.get("statusCode"));
|
||||
// prefer numeric status field if present
|
||||
if (status.matches("\\d+")) {
|
||||
try { outcomeCode = Integer.parseInt(status); } catch (NumberFormatException ignore) {}
|
||||
}
|
||||
// if not present, fall back to statusCode
|
||||
if (outcomeCode == 0 && scObj != null) {
|
||||
try { outcomeCode = Integer.parseInt(String.valueOf(scObj)); } catch (NumberFormatException ignore) {}
|
||||
}
|
||||
// default to 200 when nothing provided
|
||||
if (outcomeCode == 0) outcomeCode = 200;
|
||||
|
||||
String message = String.valueOf(payload.getOrDefault("message", top.getOrDefault("message", "")));
|
||||
|
||||
// Map outcome codes according to provided table:
|
||||
// Success: 200
|
||||
// Success without warnings: 205
|
||||
// Warning -> success (fraud accepted): 206 (treat as success)
|
||||
// Warning -> failed (fraud rejected): 207 (treat as failure)
|
||||
// Transaction processing: 198 (treat as pending/processing)
|
||||
// Fail/Exception: 417 -> failure
|
||||
// Failed: 99 -> failure
|
||||
// Rejected by acquirer: 197 -> failure
|
||||
// Declined: 194 -> failure
|
||||
// Auth success but recurring error: 193 -> failure
|
||||
// Warning: 1003 -> warning (non-fatal)
|
||||
|
||||
// Handle special cases
|
||||
if (outcomeCode == 200 || outcomeCode == 205 || outcomeCode == 206) {
|
||||
// success - build apiResponse from wrapper or direct payload
|
||||
if (top.containsKey("message") && (top.containsKey("responseData") || top.containsKey("data"))) {
|
||||
apiResponse = objectMapper.convertValue(top, PaymentStartApiResponse.class);
|
||||
} else {
|
||||
Map<String, Object> dataMap = payload;
|
||||
PaymentStartApiResponse.ResponseData rd = new PaymentStartApiResponse.ResponseData();
|
||||
rd.setAmount(String.valueOf(dataMap.getOrDefault("amount", "")));
|
||||
rd.setOrderNo(String.valueOf(dataMap.getOrDefault("orderNo", dataMap.getOrDefault("order_no", ""))));
|
||||
rd.setCreatedOn(String.valueOf(dataMap.getOrDefault("created_on", dataMap.getOrDefault("createdOn", ""))));
|
||||
rd.setQrString(String.valueOf(dataMap.getOrDefault("qrString", dataMap.getOrDefault("qr_string", ""))));
|
||||
rd.setMid(String.valueOf(dataMap.getOrDefault("mid", "")));
|
||||
rd.setTxnId(String.valueOf(dataMap.getOrDefault("txnId", dataMap.getOrDefault("txn_id", ""))));
|
||||
|
||||
apiResponse = new PaymentStartApiResponse();
|
||||
apiResponse.setMessage(String.valueOf(top.getOrDefault("message", "SUCCESS")));
|
||||
apiResponse.setStatusCode(String.valueOf(outcomeCode));
|
||||
apiResponse.setResponseData(rd);
|
||||
}
|
||||
|
||||
helper.updateInboundLogSuccess(inboundLog, respBody, String.valueOf(outcomeCode));
|
||||
// proceed normally
|
||||
} else if (outcomeCode == 198) {
|
||||
// transaction processing - treat as non-final success/pending
|
||||
helper.updateInboundLogSuccess(inboundLog, respBody, String.valueOf(outcomeCode));
|
||||
return ResponseModel.builder()
|
||||
.status(BBPSConstant.SENT_TO_PROCESSOR_STATUS)
|
||||
.statusCode(outcomeCode)
|
||||
.message(message == null || message.isEmpty() ? "Transaction processing" : message)
|
||||
.data(null)
|
||||
.build();
|
||||
} else if (outcomeCode == 1003) {
|
||||
// warning - return a WARNING response; don't throw immediately
|
||||
helper.updateInboundLogSuccess(inboundLog, respBody, String.valueOf(outcomeCode));
|
||||
return ResponseModel.builder()
|
||||
.status("WARNING")
|
||||
.statusCode(outcomeCode)
|
||||
.message(message == null || message.isEmpty() ? "Warning from merchant" : message)
|
||||
.data(null)
|
||||
.build();
|
||||
} else if (outcomeCode == 207) {
|
||||
// Fraud rejected - explicit failure, handle exception
|
||||
helper.updateInboundLogFailure(inboundLog, respBody, String.valueOf(outcomeCode));
|
||||
throw new CustomException(message == null || message.isEmpty() ? "Fraud Rejected" : message,
|
||||
"FAILED", outcomeCode, respBody);
|
||||
} else {
|
||||
// Other failure codes (417,99,197,194,193 etc.)
|
||||
helper.updateInboundLogFailure(inboundLog, respBody, String.valueOf(outcomeCode));
|
||||
throw new CustomException(message == null || message.isEmpty() ? "Upstream failure" : message,
|
||||
"FAILED", outcomeCode, respBody);
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
LOGGER.error("Error parsing payment start API response JSON: {}", e.getMessage(), e);
|
||||
helper.updateInboundLogFailure(inboundLog, respBody, BBPSConstant.JSON_ERROR);
|
||||
throw new CustomException("Invalid JSON received from payment API");
|
||||
}
|
||||
|
||||
// Save record
|
||||
bbpsMapperHelper.savePaymentStartRecord(request, apiResponse, txnId, orderNo);
|
||||
|
||||
// Prepare DTO
|
||||
PaymentStartReturnDto responseData = new PaymentStartReturnDto();
|
||||
responseData.setAmount(apiResponse.getResponseData().getAmount());
|
||||
responseData.setCreated_on(apiResponse.getResponseData().getCreatedOn());
|
||||
responseData.setOrderNo(apiResponse.getResponseData().getOrderNo());
|
||||
responseData.setQrString(apiResponse.getResponseData().getQrString());
|
||||
responseData.setTxnId(apiResponse.getResponseData().getTxnId());
|
||||
|
||||
helper.updateInboundLogSuccess(inboundLog, respBody,
|
||||
apiResponse.getStatusCode() == null ? "200" : apiResponse.getStatusCode().toString());
|
||||
|
||||
return ResponseModel.builder()
|
||||
.status("SUCCESS")
|
||||
.statusCode(httpCode)
|
||||
.message(apiResponse.getMessage())
|
||||
.data(responseData)
|
||||
.build();
|
||||
}
|
||||
|
||||
private PaymentDetailSentRequest createPaymentSentRequest(PaymentStartUserRequest request) {
|
||||
PaymentDetailSentRequest sent = new PaymentDetailSentRequest();
|
||||
sent.setAmount(request.getAmount());
|
||||
sent.setCurrency(request.getCurrency());
|
||||
sent.setEmailId(request.getEmailId());
|
||||
sent.setUserId(request.getMid());
|
||||
sent.setCustomerVpa(request.getCustomerVpa());
|
||||
sent.setDateOfReg("2025-12-31");
|
||||
String effectiveMid = (request.getMid() != null && !request.getMid().isEmpty()) ? request.getMid() : BBPSConstant.mid;
|
||||
sent.setMid(BBPSConstant.mid);
|
||||
sent.setMobileNo(request.getMobileNo());
|
||||
sent.setRespUrl(BBPSConstant.callbackurl);
|
||||
sent.setTxnReqType("S");
|
||||
sent.setName(request.getName());
|
||||
sent.setUdf1(request.getUdf1());
|
||||
sent.setUdf2(request.getUdf2());
|
||||
sent.setUdf3(request.getUdf3());
|
||||
sent.setUdf4(request.getUdf4());
|
||||
sent.setUdf5(request.getUdf5());
|
||||
sent.setUdf6(request.getUdf6());
|
||||
sent.setUdf7(request.getUdf7());
|
||||
sent.setUdf8(request.getUdf8());
|
||||
sent.setUdf9(request.getUdf9());
|
||||
sent.setUdf10(request.getUdf10());
|
||||
sent.setUdf11(request.getUdf11());
|
||||
sent.setUdf12(request.getUdf12());
|
||||
sent.setUdf13(request.getUdf13());
|
||||
sent.setUdf14(request.getUdf14());
|
||||
return sent;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user