update code resolve conflict
This commit is contained in:
@@ -12,9 +12,10 @@ import com.billpaymentservice.bbps.dto.ResponseModel;
|
||||
import com.billpaymentservice.bbps.dto.request.BillPaymentRequest;
|
||||
import com.billpaymentservice.bbps.dto.request.TransactionStatusRequest;
|
||||
import com.billpaymentservice.bbps.dto.request.TrasactionStatusByClientReqIdRequest;
|
||||
import com.billpaymentservice.bbps.dto.response.FetchBillValidateResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.TransactionStatusResponse;
|
||||
import com.billpaymentservice.bbps.service.PaymentService;
|
||||
import com.billpaymentservice.bbps.service.PaymentStartService;
|
||||
import com.billpaymentservice.bbps.dto.request.PaymentStartUserRequest;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/agent/payment")
|
||||
@@ -25,9 +26,12 @@ public class PaymentController {
|
||||
*/
|
||||
|
||||
private final PaymentService paymentService;
|
||||
private final PaymentStartService paymentStartService;
|
||||
|
||||
public PaymentController(PaymentService paymentService) {
|
||||
// New constructor used by Spring to inject both services
|
||||
public PaymentController(PaymentService paymentService, PaymentStartService paymentStartService) {
|
||||
this.paymentService = paymentService;
|
||||
this.paymentStartService = paymentStartService;
|
||||
}
|
||||
|
||||
@PostMapping(value = "/intiatePayment", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@@ -62,5 +66,15 @@ public class PaymentController {
|
||||
return ResponseEntity.ok(genralResp);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@PostMapping(value = "/startPayment", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<ResponseModel> startPayment(@Validated @RequestBody PaymentStartUserRequest paymentStartUserRequest) {
|
||||
if (this.paymentStartService == null) {
|
||||
// Defensive: if bean not injected, return failure
|
||||
return ResponseEntity.badRequest().body(new ResponseModel("PaymentStartService not available", "FAILED", 400, null));
|
||||
}
|
||||
ResponseModel response = paymentStartService.startPayment(paymentStartUserRequest);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.billpaymentservice.bbps.controller;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.billpaymentservice.bbps.dto.ResponseModel;
|
||||
import com.billpaymentservice.bbps.dto.request.PaymentStartUserRequest;
|
||||
import com.billpaymentservice.bbps.service.PaymentStartService;
|
||||
|
||||
@RestController
|
||||
public class PaymentStartController {
|
||||
private final PaymentStartService paymentStartService;
|
||||
|
||||
public PaymentStartController(PaymentStartService paymentStartService) {
|
||||
this.paymentStartService = paymentStartService;
|
||||
}
|
||||
|
||||
@PostMapping(value = "/startWebPayment", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<ResponseModel> startPayment(@Validated @RequestBody PaymentStartUserRequest paymentStartUserRequest) {
|
||||
if (this.paymentStartService == null) {
|
||||
// Defensive: if bean not injected, return failure
|
||||
return ResponseEntity.badRequest().body(new ResponseModel("PaymentStartService not available", "FAILED", 400, null));
|
||||
}
|
||||
ResponseModel response = paymentStartService.startPayment(paymentStartUserRequest);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.billpaymentservice.bbps.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PaymentStartReturnDto {
|
||||
private String amount;
|
||||
private String orderNo;
|
||||
private String created_on;
|
||||
private String qrString;
|
||||
private String txnId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.billpaymentservice.bbps.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PaymentStatusDataResponse {
|
||||
private String amount;
|
||||
private String orderNo;
|
||||
private String created_on;
|
||||
private String qrString;
|
||||
private String mid;
|
||||
private String txnId;
|
||||
|
||||
}
|
||||
@@ -53,4 +53,8 @@ public abstract class BaseClass {
|
||||
private String udf9;
|
||||
|
||||
private String udf10;
|
||||
private String udf11;
|
||||
private String udf12;
|
||||
private String udf13;
|
||||
private String udf14;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.billpaymentservice.bbps.dto.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
// DTO representing the user request payload described by the user
|
||||
public class PaymentStartUserRequest extends BaseClass implements Serializable {
|
||||
private String amount;
|
||||
private String currency;
|
||||
private String emailId;
|
||||
private String customerVpa;
|
||||
private String mobileNo;
|
||||
private String respUrl;
|
||||
private String txnReqType;
|
||||
private String name;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.billpaymentservice.bbps.dto.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import lombok.ToString;
|
||||
|
||||
@ToString
|
||||
public class PaymentStartApiResponse {
|
||||
|
||||
private String message;
|
||||
private String statusCode;
|
||||
private ResponseData responseData;
|
||||
|
||||
public PaymentStartApiResponse() {
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public void setStatusCode(String statusCode) {
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public ResponseData getResponseData() {
|
||||
return responseData;
|
||||
}
|
||||
|
||||
public void setResponseData(ResponseData responseData) {
|
||||
this.responseData = responseData;
|
||||
}
|
||||
@ToString
|
||||
public static class ResponseData {
|
||||
private String amount;
|
||||
private String orderNo;
|
||||
|
||||
@JsonProperty("created_on")
|
||||
private String createdOn;
|
||||
|
||||
private String qrString;
|
||||
private String mid;
|
||||
private String txnId;
|
||||
|
||||
public ResponseData() {
|
||||
}
|
||||
|
||||
public String getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(String amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getOrderNo() {
|
||||
return orderNo;
|
||||
}
|
||||
|
||||
public void setOrderNo(String orderNo) {
|
||||
this.orderNo = orderNo;
|
||||
}
|
||||
|
||||
public String getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
public void setCreatedOn(String createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
}
|
||||
|
||||
public String getQrString() {
|
||||
return qrString;
|
||||
}
|
||||
|
||||
public void setQrString(String qrString) {
|
||||
this.qrString = qrString;
|
||||
}
|
||||
|
||||
public String getMid() {
|
||||
return mid;
|
||||
}
|
||||
|
||||
public void setMid(String mid) {
|
||||
this.mid = mid;
|
||||
}
|
||||
|
||||
public String getTxnId() {
|
||||
return txnId;
|
||||
}
|
||||
|
||||
public void setTxnId(String txnId) {
|
||||
this.txnId = txnId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.billpaymentservice.bbps.dto.response;
|
||||
import com.billpaymentservice.bbps.dto.PaymentStatusDataResponse;
|
||||
|
||||
public class PaymentStatusResponse {
|
||||
private String message;
|
||||
private String statusCode;
|
||||
private PaymentStatusDataResponse data;
|
||||
|
||||
public PaymentStatusResponse() {}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public void setStatusCode(String statusCode) {
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public PaymentStatusDataResponse getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(PaymentStatusDataResponse data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.billpaymentservice.bbps.dto.sentRequest;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
public class PaymentDetailSentRequest {
|
||||
|
||||
private String amount;
|
||||
private String currency;
|
||||
private String emailId;
|
||||
private String userId;
|
||||
private String customerVpa;
|
||||
private String dateOfReg;
|
||||
private String enckey;
|
||||
private String mid;
|
||||
private String mobileNo;
|
||||
private String orderNo;
|
||||
private String respUrl;
|
||||
private String txnReqType;
|
||||
private String name;
|
||||
private String udf1;
|
||||
private String udf2;
|
||||
private String udf3;
|
||||
private String udf4;
|
||||
private String udf5;
|
||||
private String udf6;
|
||||
private String udf7;
|
||||
private String udf8;
|
||||
private String udf9;
|
||||
private String udf10;
|
||||
private String udf11;
|
||||
private String udf12;
|
||||
private String udf13;
|
||||
private String udf14;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.billpaymentservice.bbps.dto.sentRequest;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class PaymentRequestPayload {
|
||||
|
||||
private String mid;
|
||||
private String payload;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.billpaymentservice.bbps.entites;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "payment_start_record")
|
||||
public class PaymentStartRecord {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "request_id", unique = true, nullable = false)
|
||||
private String requestId;
|
||||
@Column(name = "client_mid", nullable = false)
|
||||
private String clientMid;
|
||||
|
||||
@Column(name = "client_user_id")
|
||||
private String clientUserId;
|
||||
|
||||
@Column(name = "internal_txn_id", unique = true, nullable = false)
|
||||
private String internalTxnId;
|
||||
|
||||
@Column(name = "order_no", unique = true, nullable = false)
|
||||
private String orderNo;
|
||||
|
||||
@Column(name = "amount", nullable = false)
|
||||
private String amount;
|
||||
|
||||
@Column(name = "mid", nullable = false)
|
||||
private String mid;
|
||||
|
||||
@Column(name = "txn_id", unique = true, nullable = false)
|
||||
private String txnId;
|
||||
|
||||
@Column(name = "qr_string", columnDefinition = "TEXT")
|
||||
private String qrString;
|
||||
|
||||
@Column(name = "created_on", nullable = false)
|
||||
private String createdOn;
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.billpaymentservice.bbps.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.billpaymentservice.bbps.entites.PaymentStartRecord;
|
||||
|
||||
@Repository
|
||||
public interface PaymentStartRecordRepository extends JpaRepository<PaymentStartRecord, Long> {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.billpaymentservice.bbps.service;
|
||||
|
||||
import com.billpaymentservice.bbps.dto.ResponseModel;
|
||||
import com.billpaymentservice.bbps.dto.request.PaymentStartUserRequest;
|
||||
|
||||
public interface PaymentStartService {
|
||||
ResponseModel startPayment(PaymentStartUserRequest request);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -151,5 +151,9 @@ public class BBPSConstant {
|
||||
public static final long BILL_FETCH_DELAY_MS = 5000L; // used after initiate bill fetch
|
||||
public static final long BILL_VALIDATE_DELAY_MS = 12000L; // used after initiate bill validate
|
||||
public static final long PAYMENT_STATUS_DELAY_MS = 9000L; // used after initiate payment
|
||||
|
||||
|
||||
public static final String enckey="zk52olsyr9fl95h50eus8bhtyhoo5lp7";
|
||||
public static final String mid="Test-By-Aditya-1001";
|
||||
public static final String callbackurl= "https://checkout.solwio.in/PGPayU/payu/callback";
|
||||
public static final String companyName= "techwork technology";
|
||||
}
|
||||
@@ -43,12 +43,14 @@ import com.billpaymentservice.bbps.dto.request.ComplaintRequestDTO;
|
||||
import com.billpaymentservice.bbps.dto.request.FetchBillRequest;
|
||||
import com.billpaymentservice.bbps.dto.request.FetchBillValidatestRequest;
|
||||
import com.billpaymentservice.bbps.dto.request.GetTicketLatestStausRequest;
|
||||
import com.billpaymentservice.bbps.dto.request.PaymentStartUserRequest;
|
||||
import com.billpaymentservice.bbps.dto.response.AmountOptionsResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.BillDataResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.ClientReqIdResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.ComplaintHistoryStatusResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.ComplaintResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.FetchBillValidateResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.PaymentStartApiResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.PlanResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.TicketCheckStatusResponse;
|
||||
import com.billpaymentservice.bbps.dto.response.ViewAllComplaintsResponse;
|
||||
@@ -85,6 +87,7 @@ import com.billpaymentservice.bbps.entites.CustomerParamBill;
|
||||
import com.billpaymentservice.bbps.entites.CustomerParamBillValidation;
|
||||
import com.billpaymentservice.bbps.entites.CustomerParamGroupById;
|
||||
import com.billpaymentservice.bbps.entites.GroupParam;
|
||||
import com.billpaymentservice.bbps.entites.PaymentStartRecord;
|
||||
import com.billpaymentservice.bbps.entites.Plan;
|
||||
import com.billpaymentservice.bbps.entites.PlanCategorySubType;
|
||||
import com.billpaymentservice.bbps.entites.PlanResponses;
|
||||
@@ -109,11 +112,14 @@ import com.billpaymentservice.bbps.repository.ComplaintStatusRepository;
|
||||
import com.billpaymentservice.bbps.repository.ContactMasterDataRepository;
|
||||
import com.billpaymentservice.bbps.repository.CustomerParamGroupByBillerIdRepository;
|
||||
import com.billpaymentservice.bbps.repository.FetchBillValidateRepository;
|
||||
import com.billpaymentservice.bbps.repository.PaymentStartRecordRepository;
|
||||
import com.billpaymentservice.bbps.repository.PlanResponseRepository;
|
||||
import com.billpaymentservice.bbps.repository.ReOpenComplaintRepository;
|
||||
import com.billpaymentservice.bbps.repository.TicketDispositionRepository;
|
||||
import com.billpaymentservice.bbps.repository.ViewAllComplainTicketDetailRepository;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
|
||||
@Component
|
||||
public class BillerMapperHelper {
|
||||
|
||||
@@ -139,6 +145,7 @@ public class BillerMapperHelper {
|
||||
private final BillMasterRepository billMasterRepository;
|
||||
private final BillValidationRepository billValidationRepository;
|
||||
private final ComplaintResponseRepository complaintResponseRepository;
|
||||
private final PaymentStartRecordRepository paymentStartRecordRepository;
|
||||
|
||||
public BillerMapperHelper(BillerCategoryWiseRepository billerRepo,
|
||||
CustomerParamGroupByBillerIdRepository customerParamGroupByBillerIdRepo,
|
||||
@@ -154,8 +161,10 @@ public class BillerMapperHelper {
|
||||
ViewAllComplainTicketDetailRepository viewAllComplainTicketDetailRepository,
|
||||
ContactMasterDataRepository contactMasterDataRepository, BBPSMasterDataRepo bbpsMasterDataRepo,
|
||||
BillerDataRepository billerDataRespository, BillMasterRepository billMasterRepository,
|
||||
BillValidationRepository billValidationRepository,
|
||||
ComplaintResponseRepository complaintResponseRepository) {
|
||||
BillValidationRepository billValidationRepository, ComplaintResponseRepository complaintResponseRepository,
|
||||
PaymentStartRecordRepository paymentStartRecordRepository) {
|
||||
|
||||
this.paymentStartRecordRepository = paymentStartRecordRepository;
|
||||
this.billerRepo = billerRepo;
|
||||
this.customerParamGroupByBillerIdRepo = customerParamGroupByBillerIdRepo;
|
||||
this.amountOptionByBillerIdRepository = amountOptionByBillerIdRepository;
|
||||
@@ -1071,6 +1080,23 @@ public class BillerMapperHelper {
|
||||
return forward;
|
||||
}
|
||||
|
||||
public void savePaymentStartRecord(PaymentStartUserRequest request, PaymentStartApiResponse apiResponse,
|
||||
String txnId, String orderNo) {
|
||||
PaymentStartRecord record = new PaymentStartRecord();
|
||||
record.setOrderNo(orderNo);
|
||||
record.setRequestId(request.getReqId());
|
||||
record.setClientMid(request.getMid());
|
||||
record.setClientUserId(request.getClientUserId());
|
||||
record.setInternalTxnId(txnId);
|
||||
record.setAmount(apiResponse.getResponseData().getAmount());
|
||||
record.setMid(apiResponse.getResponseData().getMid());
|
||||
record.setTxnId(apiResponse.getResponseData().getTxnId());
|
||||
record.setQrString(apiResponse.getResponseData().getQrString());
|
||||
record.setCreatedOn(apiResponse.getResponseData().getCreatedOn());
|
||||
|
||||
paymentStartRecordRepository.save(record);
|
||||
}
|
||||
|
||||
public TransactionHistoryMasterDTO toDTO(TransactionMaster transactionMaster) {
|
||||
if (transactionMaster == null) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.billpaymentservice.bbps.util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class EncryptionUtil {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EncryptionUtil.class);
|
||||
|
||||
/**
|
||||
* Encrypts plaintext using AES/CBC/PKCS5Padding.
|
||||
* If the provided key length is not 16/24/32 bytes it will be adjusted to 16 bytes (padded/truncated).
|
||||
* NOTE: This follows the algorithm snippet provided by the user but pads/truncates the key to avoid
|
||||
* common runtime errors when key lengths are incorrect.
|
||||
*/
|
||||
public String encryptMData(String plaintext, String encryptKey) {
|
||||
try {
|
||||
// Ensure key length is 16 bytes (AES-128). If callers provide a longer key this will truncate.
|
||||
byte[] keyBytes = normalizeKey(encryptKey);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
|
||||
|
||||
byte[] ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
|
||||
byte[] encryptedData = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
byte[] combinedBytes = new byte[ivBytes.length + encryptedData.length];
|
||||
System.arraycopy(ivBytes, 0, combinedBytes, 0, ivBytes.length);
|
||||
System.arraycopy(encryptedData, 0, combinedBytes, ivBytes.length, encryptedData.length);
|
||||
return Base64.getEncoder().encodeToString(combinedBytes);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Exception in encrypt() : encryptMData- {} : Message- {}", encryptKey, e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] normalizeKey(String encryptKey) {
|
||||
if (encryptKey == null) {
|
||||
encryptKey = "";
|
||||
}
|
||||
byte[] bytes = encryptKey.getBytes(StandardCharsets.UTF_8);
|
||||
int targetLen = 16; // AES-128
|
||||
if (bytes.length == targetLen || bytes.length == 24 || bytes.length == 32) {
|
||||
return bytes;
|
||||
}
|
||||
byte[] normalized = new byte[targetLen];
|
||||
for (int i = 0; i < targetLen; i++) {
|
||||
if (i < bytes.length) {
|
||||
normalized[i] = bytes[i];
|
||||
} else {
|
||||
normalized[i] = 0; // pad with zeros
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
@@ -183,5 +183,14 @@ public class Helper {
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public <T> T convertJsonToObject(String json, Class<T> clazz) {
|
||||
try {
|
||||
return objectMapper.readValue(json, clazz);
|
||||
} catch (Exception e) {
|
||||
throw new CustomException("Invalid JSON from payment API", "FAILED", 400, json);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user