working web based and intent

This commit is contained in:
Lincpay Tech
2025-12-03 11:36:28 +05:30
parent 9634939982
commit e374e189a7
11 changed files with 303 additions and 84 deletions
@@ -6,6 +6,7 @@ import java.util.Map;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -17,6 +18,7 @@ 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.request.CallbackRequest;
import com.billpaymentservice.bbps.dto.response.PaymentStartApiResponse;
import com.billpaymentservice.bbps.dto.response.PaymentStatusResponse;
import com.billpaymentservice.bbps.dto.sentRequest.PaymentDetailSentRequest;
@@ -36,13 +38,15 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.billpaymentservice.bbps.entites.OutboundTraceLog;
import com.billpaymentservice.bbps.entites.BharatConnectMaster;
import com.billpaymentservice.bbps.entites.PaymentStartRecord;
@Service
public class PaymentStartServiceImpl implements PaymentStartService {
private static final Logger LOGGER = LoggerFactory.getLogger(PaymentStartServiceImpl.class);
private String uatPaymentUrl="https://uat.godemo.in/api/UATIntegration/uat/payin/paymentrequest";
private String uatPaymentUrlweb="https://uat.godemo.in/api/UATIntegration/uat/payin/paymentrequest";
private String uatPaymentUrlintent="https://uat.godemo.in/api/UATIntegration/paymentrequest/seamless";
private final PaymentStartRecordRepository paymentStartRecordRepository;
private final HttpService httpService;
@@ -69,7 +73,7 @@ public class PaymentStartServiceImpl implements PaymentStartService {
this.bbpsMapperHelper = bbpsMapperHelper;
}
@Override
public ResponseModel startPayment(PaymentStartUserRequest request) {
public ResponseModel startIntentPayment(PaymentStartUserRequest request) {
String requestId = request.getReqId();
String apiName = "StartPayment";
@@ -97,15 +101,17 @@ public class PaymentStartServiceImpl implements PaymentStartService {
PaymentRequestPayload finalPayload = new PaymentRequestPayload();
finalPayload.setMid(BBPSConstant.mid);
finalPayload.setPayload(encrypted);
String forwardJson = helper.convertObjectToJson(finalPayload);
LOGGER.info("Payment Start Request Payload: " + forwardJson);
OutboundTraceLog outboundLog =
helper.createOutboundLog(txnId, requestId, apiName, uatPaymentUrl,
helper.createOutboundLog(txnId, requestId, apiName, uatPaymentUrlintent,
BBPSConstant.HTTP_POST, forwardJson);
// --- CALL EXTERNAL API ---
Map<String, String> responseMap =
httpService.postRequest(uatPaymentUrl, forwardJson, null);
httpService.postRequest(uatPaymentUrlintent, forwardJson, null);
LOGGER.info("Payment Start Response: " + responseMap);
@@ -166,19 +172,7 @@ public class PaymentStartServiceImpl implements PaymentStartService {
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
@@ -238,7 +232,15 @@ public class PaymentStartServiceImpl implements PaymentStartService {
}
// Save record
bbpsMapperHelper.savePaymentStartRecord(request, apiResponse, txnId, orderNo);
// Determine response type: QR if qrString present, else JSON
String responseType = "JSON";
String rawResponse = respBody == null ? "" : respBody;
if (apiResponse != null && apiResponse.getResponseData() != null
&& apiResponse.getResponseData().getQrString() != null
&& !apiResponse.getResponseData().getQrString().isEmpty()) {
responseType = "QR";
}
bbpsMapperHelper.savePaymentStartRecord(request, apiResponse, txnId, orderNo, requestJson, rawResponse, responseType);
// Prepare DTO
PaymentStartReturnDto responseData = new PaymentStartReturnDto();
@@ -322,12 +324,12 @@ public class PaymentStartServiceImpl implements PaymentStartService {
"&payload=" + URLEncoder.encode(encrypted, StandardCharsets.UTF_8);
LOGGER.info("Form Payload: {}", formPayload);
OutboundTraceLog outboundLog =
helper.createOutboundLog(txnId, requestId, apiName, uatPaymentUrl,
helper.createOutboundLog(txnId, requestId, apiName, uatPaymentUrlweb,
BBPSConstant.HTTP_POST, formPayload);
// ----------- CALL API (FORM URL-ENCODED) -----------
Map<String, String> responseMap =
httpService.postFormRequest(uatPaymentUrl, formPayload);
httpService.postFormRequest(uatPaymentUrlweb, formPayload);
LOGGER.info("Payment Start Response: {}", responseMap);
@@ -350,21 +352,122 @@ public class PaymentStartServiceImpl implements PaymentStartService {
// ❗❗ PG RETURNS HTML → NO JSON PARSING REQUIRED
helper.updateInboundLogSuccess(inboundLog, respBody, "200");
// Save record with HTML (persist original request and HTML response)
String responseTypeWeb = "HTML";
String rawResponseWeb = respBody == null ? "" : respBody;
// bbpsMapperHelper.savePaymentStartRecord(request, null, txnId, orderNo, requestJson, rawResponseWeb, responseTypeWeb);
// Save record with HTML (optional)
// bbpsMapperHelper.savePaymentStartHtmlRecord(request, respBody, txnId, orderNo);
// Return HTML directly in API response
Map<String, String> result = new HashMap<>();
result.put("html", respBody);
// Return HTML directly in API response
Map<String, String> result = new HashMap<>();
result.put("html", respBody);
return ResponseModel.builder()
.status("SUCCESS")
.statusCode(200)
.message("HTML Response Received")
.data(result)
.build();
return ResponseModel.builder()
.status("SUCCESS")
.statusCode(200)
.message("HTML Response Received")
.data(result)
.build();
}
@Override
public ResponseModel handleStartCallback(CallbackRequest callbackRequest) {
String apiName = "HANDLE_START_CALLBACK";
LOGGER.info("[{}] START | payload={}", apiName, callbackRequest);
}
if (callbackRequest == null) {
LOGGER.warn("Callback payload is null");
return new ResponseModel("Invalid callback", "205", 200, null);
}
String mid = callbackRequest.getMid();
String encryptedData = callbackRequest.getData();
String signature = callbackRequest.getSignature();
// Decrypt data
String decrypted = encryptionUtil.decryptMData(encryptedData, BBPSConstant.enckey);
if (decrypted == null) {
LOGGER.error("Failed to decrypt callback payload for mid={}", mid);
return new ResponseModel("Decryption failed", "207", 200, null);
}
LOGGER.info("Decrypted callback data: {}", decrypted);
// Parse decrypted JSON
Map<String, Object> payloadMap;
try {
payloadMap = objectMapper.readValue(decrypted, new TypeReference<Map<String, Object>>(){});
} catch (JsonProcessingException e) {
LOGGER.error("Failed to parse decrypted callback JSON: {}", e.getMessage(), e);
return new ResponseModel("Invalid decrypted JSON", "207", 200, null);
}
String txnId = String.valueOf(payloadMap.getOrDefault("txnId", payloadMap.getOrDefault("txn_id", "")));
String orderNo = String.valueOf(payloadMap.getOrDefault("orderNo", payloadMap.getOrDefault("order_no", "")));
String txnStatus = String.valueOf(payloadMap.getOrDefault("txnStatus", payloadMap.getOrDefault("txn_status", payloadMap.getOrDefault("status", ""))));
// Compute checksum: Mid + txnId + orderNo + txnStatus
String checksumStr = mid + txnId + orderNo + txnStatus;
String computedChecksum = encryptionUtil.getChecksumCRC32(checksumStr);
boolean signatureMatches = false;
if (computedChecksum != null && signature != null) {
signatureMatches = computedChecksum.equals(signature) || computedChecksum.equals(String.valueOf(Long.parseLong(signature)));
}
// Find DB record
Optional<PaymentStartRecord> recordOpt = Optional.empty();
if (orderNo != null && !orderNo.isEmpty()) {
recordOpt = paymentStartRecordRepository.findByOrderNo(orderNo);
}
if (recordOpt.isEmpty() && txnId != null && !txnId.isEmpty()) {
recordOpt = paymentStartRecordRepository.findByTxnId(txnId);
}
PaymentStartRecord record = recordOpt.orElse(null);
if (record == null) {
LOGGER.warn("No PaymentStartRecord found for orderNo={} txnId={}", orderNo, txnId);
// still return 205 to acknowledge receipt
return new ResponseModel("No matching record", "205", 200, null);
}
// Update record with bank response and signature
record.setBankResponse(decrypted);
record.setSignature(signature);
// update txn status and callback timestamp
record.setTxnStatus(txnStatus);
record.setCallbackReceivedOn(java.time.LocalDateTime.now().toString());
String merchantStatus;
if (!signatureMatches) {
LOGGER.error("Signature mismatch. computed={} provided={}", computedChecksum, signature);
record.setCallbackStatus("SIGNATURE_MISMATCH");
paymentStartRecordRepository.save(record);
merchantStatus = "207"; // treat as rejected/failure
LOGGER.info("[{}] END | returning status={}", apiName, merchantStatus);
return new ResponseModel("Signature mismatch", merchantStatus, 200, null);
}
// signature ok - decide response based on txnStatus
if (txnStatus.equalsIgnoreCase("SUCCESS") || txnStatus.equalsIgnoreCase("SUCCESSFUL") || txnStatus.equalsIgnoreCase("SUCCESSFULL")) {
record.setCallbackStatus("SUCCESS");
paymentStartRecordRepository.save(record);
merchantStatus = "206"; // accepted by merchant
} else if (txnStatus.equalsIgnoreCase("FAILED") || txnStatus.equalsIgnoreCase("FAIL")) {
record.setCallbackStatus("FAILED");
paymentStartRecordRepository.save(record);
merchantStatus = "207"; // rejected
} else {
record.setCallbackStatus("RECEIVED");
paymentStartRecordRepository.save(record);
merchantStatus = "205"; // generic ack
}
LOGGER.info("Callback processed for orderNo={} txnId={} status={} returning merchantStatus={}", orderNo, txnId, txnStatus, merchantStatus);
LOGGER.info("[{}] END", apiName);
return new ResponseModel("Callback processed", merchantStatus, 200, null);
}
}