474 lines
22 KiB
Java
474 lines
22 KiB
Java
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 java.util.Optional;
|
|
|
|
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.request.CallbackRequest;
|
|
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;
|
|
import com.billpaymentservice.bbps.entites.PaymentStartRecord;
|
|
|
|
@Service
|
|
public class PaymentStartServiceImpl implements PaymentStartService {
|
|
|
|
private static final Logger LOGGER = LoggerFactory.getLogger(PaymentStartServiceImpl.class);
|
|
|
|
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;
|
|
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 startIntentPayment(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);
|
|
LOGGER.info("Payment Start Request Payload: " + forwardJson);
|
|
OutboundTraceLog outboundLog =
|
|
helper.createOutboundLog(txnId, requestId, apiName, uatPaymentUrlintent,
|
|
BBPSConstant.HTTP_POST, forwardJson);
|
|
|
|
// --- CALL EXTERNAL API ---
|
|
Map<String, String> responseMap =
|
|
httpService.postRequest(uatPaymentUrlintent, 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", "")));
|
|
|
|
|
|
// 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
|
|
// 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();
|
|
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;
|
|
}
|
|
|
|
@Override
|
|
public ResponseModel startWebPayment(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);
|
|
|
|
// ----------- BUILD x-www-form-urlencoded PAYLOAD -----------
|
|
String formPayload =
|
|
"mid=" + URLEncoder.encode(BBPSConstant.mid, StandardCharsets.UTF_8) +
|
|
"&payload=" + URLEncoder.encode(encrypted, StandardCharsets.UTF_8);
|
|
LOGGER.info("Form Payload: {}", formPayload);
|
|
OutboundTraceLog outboundLog =
|
|
helper.createOutboundLog(txnId, requestId, apiName, uatPaymentUrlweb,
|
|
BBPSConstant.HTTP_POST, formPayload);
|
|
|
|
// ----------- CALL API (FORM URL-ENCODED) -----------
|
|
Map<String, String> responseMap =
|
|
httpService.postFormRequest(uatPaymentUrlweb, formPayload);
|
|
|
|
LOGGER.info("Payment Start Response: {}", responseMap);
|
|
|
|
int httpCode = Integer.parseInt(responseMap.getOrDefault("respCode", "500"));
|
|
String respBody = responseMap.getOrDefault("data", "");
|
|
|
|
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);
|
|
}
|
|
|
|
// ---- EMPTY RESPONSE ----
|
|
if (respBody.isEmpty()) {
|
|
helper.updateInboundLogFailure(inboundLog, "Empty response from PG", "500");
|
|
throw new CustomException("Empty response from PG", "FAILED", 500, null);
|
|
}
|
|
|
|
// ❗❗ 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);
|
|
|
|
// 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();
|
|
}
|
|
|
|
@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);
|
|
}
|
|
|
|
|
|
}
|