From 6f53dedbe1b15b9d0f7c301352719d5ce6224287 Mon Sep 17 00:00:00 2001 From: Lincpay Tech Date: Wed, 26 Nov 2025 17:17:04 +0530 Subject: [PATCH] added login with otp and verify otp --- .../bbps/controller/AuthController.java | 51 +++++ .../bbps/controller/PaymentController.java | 2 + .../bbps/dto/auth/AuthResponse.java | 51 +++++ .../bbps/dto/auth/LoginRequest.java | 19 ++ .../bbps/dto/auth/OtpSendResponse.java | 29 +++ .../bbps/dto/auth/RegisterRequest.java | 14 ++ .../bbps/dto/auth/UserDto.java | 20 ++ .../bbps/dto/auth/VerifyOtpRequest.java | 30 +++ .../bbps/dto/request/TransactionHistory.java | 5 + .../bbps/entites/UserEntity.java | 42 ++++ .../bbps/repository/UserRepository.java | 13 ++ .../bbps/service/AuthService.java | 15 ++ .../bbps/serviceImpl/AgentServiceImpl.java | 4 +- .../bbps/serviceImpl/AuthServiceImpl.java | 89 +++++++++ .../billpaymentservice/bbps/util/Helper.java | 12 ++ .../bbps/util/OtpClient.java | 186 ++++++++++++++++++ .../resources/application-local.properties | 12 +- src/main/resources/application.properties | 6 + 18 files changed, 595 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/billpaymentservice/bbps/controller/AuthController.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/LoginRequest.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/OtpSendResponse.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/VerifyOtpRequest.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/request/TransactionHistory.java create mode 100644 src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java create mode 100644 src/main/java/com/billpaymentservice/bbps/repository/UserRepository.java create mode 100644 src/main/java/com/billpaymentservice/bbps/service/AuthService.java create mode 100644 src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java create mode 100644 src/main/java/com/billpaymentservice/bbps/util/OtpClient.java diff --git a/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java b/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java new file mode 100644 index 0000000..56c7367 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java @@ -0,0 +1,51 @@ +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.CrossOrigin; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.billpaymentservice.bbps.dto.auth.AuthResponse; +import com.billpaymentservice.bbps.dto.auth.LoginRequest; +import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; +import com.billpaymentservice.bbps.dto.auth.RegisterRequest; +import com.billpaymentservice.bbps.dto.auth.VerifyOtpRequest; +import com.billpaymentservice.bbps.service.AuthService; + +import lombok.extern.slf4j.Slf4j; + +@RestController +@RequestMapping("/auth") +@CrossOrigin(origins = "*") +@Slf4j +public class AuthController { + + private final AuthService authService; + + public AuthController(AuthService authService) { + this.authService = authService; + } + + @PostMapping(value = "/sendOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity sendOtp(@Validated @RequestBody LoginRequest request) { + log.info("Received sendOtp request for mobile: {}", request.getMobile()); + OtpSendResponse resp = authService.sendOtp(request); + return ResponseEntity.ok(resp); + } + + @PostMapping(value = "/verifyOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity verifyOtp(@Validated @RequestBody VerifyOtpRequest request) { + AuthResponse resp = authService.verifyOtp(request); + return ResponseEntity.ok(resp); + } + + @PostMapping(value = "/register", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity register(@Validated @RequestBody RegisterRequest request) { + AuthResponse resp = authService.registerUser(request); + return ResponseEntity.ok(resp); + } +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/controller/PaymentController.java b/src/main/java/com/billpaymentservice/bbps/controller/PaymentController.java index decc81c..fdfaf84 100644 --- a/src/main/java/com/billpaymentservice/bbps/controller/PaymentController.java +++ b/src/main/java/com/billpaymentservice/bbps/controller/PaymentController.java @@ -54,11 +54,13 @@ public class PaymentController { return ResponseEntity.ok(response); } + @PostMapping(value="/callback/paymentIntiate", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity handleBillValidateCallback(@RequestBody TransactionStatusResponse transactionStatusResponse) { ResponseModel genralResp=paymentService.handlePaymentIntiateCallback(transactionStatusResponse); // Return a response indicating successful receipt return ResponseEntity.ok(genralResp); } + } diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java new file mode 100644 index 0000000..a88d366 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java @@ -0,0 +1,51 @@ +package com.billpaymentservice.bbps.dto.auth; + +import com.billpaymentservice.bbps.dto.auth.UserDto; + +public class AuthResponse { + private boolean success; + private String message; + private boolean userExists; + private UserDto user; + + public AuthResponse() {} + + public AuthResponse(boolean success, String message, boolean userExists, UserDto user) { + this.success = success; + this.message = message; + this.userExists = userExists; + this.user = user; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public boolean isUserExists() { + return userExists; + } + + public void setUserExists(boolean userExists) { + this.userExists = userExists; + } + + public UserDto getUser() { + return user; + } + + public void setUser(UserDto user) { + this.user = user; + } +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/LoginRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/LoginRequest.java new file mode 100644 index 0000000..8d8a65a --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/LoginRequest.java @@ -0,0 +1,19 @@ +package com.billpaymentservice.bbps.dto.auth; + +public class LoginRequest { + private String mobile; + + public LoginRequest() {} + + public LoginRequest(String mobile) { + this.mobile = mobile; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/OtpSendResponse.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/OtpSendResponse.java new file mode 100644 index 0000000..67dc6ff --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/OtpSendResponse.java @@ -0,0 +1,29 @@ +package com.billpaymentservice.bbps.dto.auth; + +public class OtpSendResponse { + private boolean success; + private String message; + + public OtpSendResponse() {} + + public OtpSendResponse(boolean success, String message) { + this.success = success; + this.message = message; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java new file mode 100644 index 0000000..ee156a1 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java @@ -0,0 +1,14 @@ +package com.billpaymentservice.bbps.dto.auth; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RegisterRequest { + private String mobile; + private String name; + private String email; + private int age; + +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java new file mode 100644 index 0000000..1c35570 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java @@ -0,0 +1,20 @@ +package com.billpaymentservice.bbps.dto.auth; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class UserDto { + private Long id; + private String mobile; + private String name; + private String email; + private int age; + + +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/VerifyOtpRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/VerifyOtpRequest.java new file mode 100644 index 0000000..a52c072 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/VerifyOtpRequest.java @@ -0,0 +1,30 @@ +package com.billpaymentservice.bbps.dto.auth; + +public class VerifyOtpRequest { + private String mobile; + private String otp; + + public VerifyOtpRequest() { + } + + public VerifyOtpRequest(String mobile, String otp) { + this.mobile = mobile; + this.otp = otp; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getOtp() { + return otp; + } + + public void setOtp(String otp) { + this.otp = otp; + } +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/TransactionHistory.java b/src/main/java/com/billpaymentservice/bbps/dto/request/TransactionHistory.java new file mode 100644 index 0000000..a879f88 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/TransactionHistory.java @@ -0,0 +1,5 @@ +package com.billpaymentservice.bbps.dto.request; + +public class TransactionHistory { + +} diff --git a/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java b/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java new file mode 100644 index 0000000..ab454eb --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java @@ -0,0 +1,42 @@ +package com.billpaymentservice.bbps.entites; + +import com.billpaymentservice.bbps.audit.Auditable; + +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.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "users") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class UserEntity extends Auditable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "mobile", nullable = false, unique = true, length = 20) + private String mobile; + + @Column(name = "name", length = 150) + private String name; + + @Column(name = "email", length = 150) + private String email; + + @Column(name = "age") + private int age; + + + +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/repository/UserRepository.java b/src/main/java/com/billpaymentservice/bbps/repository/UserRepository.java new file mode 100644 index 0000000..54c7362 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/repository/UserRepository.java @@ -0,0 +1,13 @@ +package com.billpaymentservice.bbps.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.billpaymentservice.bbps.entites.UserEntity; + +@Repository +public interface UserRepository extends JpaRepository { + Optional findByMobile(String mobile); +} diff --git a/src/main/java/com/billpaymentservice/bbps/service/AuthService.java b/src/main/java/com/billpaymentservice/bbps/service/AuthService.java new file mode 100644 index 0000000..32e832e --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/service/AuthService.java @@ -0,0 +1,15 @@ +package com.billpaymentservice.bbps.service; + +import com.billpaymentservice.bbps.dto.auth.AuthResponse; +import com.billpaymentservice.bbps.dto.auth.LoginRequest; +import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; +import com.billpaymentservice.bbps.dto.auth.RegisterRequest; +import com.billpaymentservice.bbps.dto.auth.VerifyOtpRequest; +import com.billpaymentservice.bbps.entites.UserEntity; + +public interface AuthService { + OtpSendResponse sendOtp(LoginRequest request); + AuthResponse verifyOtp(VerifyOtpRequest request); + AuthResponse registerUser(RegisterRequest request); + UserEntity findByMobile(String mobile); +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java index 271bf91..a22994f 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java @@ -270,7 +270,7 @@ public class AgentServiceImpl implements AgentService { String apiName = BBPSConstant.API_INITIATE_BILL_VALIDATE; String reqId = fetchBillValidateRequest.getReqId(); String mid = fetchBillValidateRequest.getMid(); - LOGGER.info("[{}] START | reqId={} | mid={} | billerId={}", apiName, fetchBillValidateRequest, mid, + LOGGER.info("[{}] START | reqId={} | mid={} | billerId={}", apiName, fetchBillValidateRequest.getReqId(), mid, fetchBillValidateRequest.getBillerId()); String txnId = helper.generateTxnId(15); String fullUrl = agentDtaUrl + BBPSConstant.BILLER_VALIDATE_URL; @@ -395,8 +395,6 @@ public class AgentServiceImpl implements AgentService { helper.updateInboundLogSuccess(inboundLog, responseData, generalResp.getStatus()); System.out.println("responseWrapper:" + responseWrapper); mapperHelper.saveBillValidation(responseWrapper, billRequest); - LOGGER.info("Bill data saved successfully for billId: {}", billId); - return new ResponseModel(generalResp.getMessage(), generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), responseWrapper); } catch (JsonProcessingException e) { diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java new file mode 100644 index 0000000..861bcd7 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java @@ -0,0 +1,89 @@ +package com.billpaymentservice.bbps.serviceImpl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.billpaymentservice.bbps.dto.auth.AuthResponse; +import com.billpaymentservice.bbps.dto.auth.LoginRequest; +import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; +import com.billpaymentservice.bbps.dto.auth.RegisterRequest; +import com.billpaymentservice.bbps.dto.auth.UserDto; +import com.billpaymentservice.bbps.dto.auth.VerifyOtpRequest; +import com.billpaymentservice.bbps.entites.UserEntity; +import com.billpaymentservice.bbps.repository.UserRepository; +import com.billpaymentservice.bbps.service.AuthService; +import com.billpaymentservice.bbps.util.Helper; +import com.billpaymentservice.bbps.util.OtpClient; + +import java.util.Optional; + +@Service +public class AuthServiceImpl implements AuthService { + + private static final Logger LOGGER = LoggerFactory.getLogger(AuthServiceImpl.class); + + private final UserRepository userRepository; + private final OtpClient otpClient; + private final Helper helper ; + + @Autowired + public AuthServiceImpl(UserRepository userRepository, OtpClient otpClient,Helper helper) { + this.userRepository = userRepository; + this.otpClient = otpClient; + this.helper = helper; + } + + @Override + public OtpSendResponse sendOtp(LoginRequest request) { + Optional existing = userRepository.findByMobile(request.getMobile()); + + if (existing.isPresent()) { + UserEntity u = existing.get(); + UserDto dto = new UserDto(u.getId(), u.getMobile(), u.getName(), u.getEmail(),u.getAge()); + return null; + } + // delegate to external OTP provider + return otpClient.sendOtp(request.getMobile()); + } + + @Override + public AuthResponse verifyOtp(VerifyOtpRequest request) { + boolean ok = otpClient.verifyOtp(request.getMobile(), request.getOtp()); + if (!ok) { + return new AuthResponse(false, "Invalid OTP", false, null); + } + + Optional userOpt = userRepository.findByMobile(request.getMobile()); + if (userOpt.isPresent()) { + UserEntity user = userOpt.get(); + UserDto dto = new UserDto(user.getId(), user.getMobile(), user.getName(), user.getEmail(),user.getAge()); + return new AuthResponse(true, "Login successful", true, dto); + } else { + return new AuthResponse(true, "OTP verified; user not found - proceed to registration", false, null); + } + } + + @Override + @Transactional + public AuthResponse registerUser(RegisterRequest request) { + Optional existing = userRepository.findByMobile(request.getMobile()); + if (existing.isPresent()) { + UserEntity u = existing.get(); + UserDto dto = new UserDto(u.getId(), u.getMobile(), u.getName(), u.getEmail(),u.getAge()); + return new AuthResponse(false, "User already exists", true, dto); + } + + UserEntity user = helper.createNewUser(request); + user = userRepository.save(user); + UserDto dto = new UserDto(user.getId(), user.getMobile(), user.getName(), user.getEmail(),user.getAge()); + return new AuthResponse(true, "Registration successful", true, dto); + } + + @Override + public UserEntity findByMobile(String mobile) { + return userRepository.findByMobile(mobile).orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/util/Helper.java b/src/main/java/com/billpaymentservice/bbps/util/Helper.java index 9949670..74a4d3f 100644 --- a/src/main/java/com/billpaymentservice/bbps/util/Helper.java +++ b/src/main/java/com/billpaymentservice/bbps/util/Helper.java @@ -8,9 +8,11 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; +import com.billpaymentservice.bbps.dto.auth.RegisterRequest; import com.billpaymentservice.bbps.entites.BBPSMastersData; import com.billpaymentservice.bbps.entites.InboundTraceLog; import com.billpaymentservice.bbps.entites.OutboundTraceLog; +import com.billpaymentservice.bbps.entites.UserEntity; import com.billpaymentservice.bbps.entites.BharatConnectMaster; import com.billpaymentservice.bbps.exception.CustomException; import com.billpaymentservice.bbps.repository.BBPSMasterDataRepo; @@ -166,4 +168,14 @@ public class Helper { return headers; } + public UserEntity createNewUser(RegisterRequest request) { + UserEntity user = new UserEntity(); + + user.setMobile(request.getMobile()); + user.setName(request.getName()); + user.setEmail(request.getEmail()); + user.setAge(request.getAge()); + return user; + } + } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java b/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java new file mode 100644 index 0000000..758ced5 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java @@ -0,0 +1,186 @@ +package com.billpaymentservice.bbps.util; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; + +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +public class OtpClient { + + private static final Logger logger = LoggerFactory.getLogger(OtpClient.class); + + private final RestTemplate restTemplate = new RestTemplate(); + + @Value("${ekyc.mobile}") + private String sendUrl; + + @Value("${ekyc.mobile.verify.otp}") + private String verifyUrl; + + // New config properties for eKYC-style OTP API + @Value("${ekyc.mobile}") + private String ekycMobileUrl; + + @Value("${ekyc.apikey}") + private String apiKey; + + @Value("${ekyc.secreteKey}") + private String secretKey; + + + /** + * Calls external API to send OTP. The implementation assumes a POST with JSON {"mobile":"..."} + * Modify headers/body as per your external API. Updated to support eKYC OTP generation logic. + */ + public OtpSendResponse sendOtp(String mobile) { + try { + logger.info("Initiating OTP send process for mobile: {}", mobile); + + logger.info("eKYC Mobile URL: {}", ekycMobileUrl); + logger.info("API Key: {}", apiKey != null && !apiKey.isEmpty()); + logger.info("Secret Key: {}", secretKey != null && !secretKey.isEmpty()); + logger.info("Send URL: {}", sendUrl); + logger.info("Verify URL: {}", verifyUrl); + logger.info("Mobile Number: {}", mobile); + + // If explicit eKYC config present, use that flow + if (ekycMobileUrl != null && !ekycMobileUrl.isEmpty()) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + // Build JSON body string as in user's snippet + String jsonBody = "{\"mobileNumber\":\"" + mobile + "\", \"apiKey\":\"" + apiKey + + "\", \"secretKey\":\"" + secretKey + "\"}"; + + HttpEntity request = new HttpEntity<>(jsonBody, headers); + + try { + ResponseEntity response = restTemplate.exchange(ekycMobileUrl, HttpMethod.POST, request, + String.class); + logger.info("eKYC OTP generation API response status: {}", response.getStatusCode()); + + if (response.getStatusCode() == HttpStatus.OK) { + logger.info("OTP generated successfully for mobile: {}", mobile); + return new OtpSendResponse(true, "OTP generated successfully"); + + } else { + logger.error("Failed to call eKYC OTP generation API: {}", response.getStatusCode()); + return new OtpSendResponse(false, "Failed to call OTP generation service"); + } + } catch (Exception e) { + logger.error("Error calling eKYC OTP generation API: {}", e.getMessage(), e); + return new OtpSendResponse(false, "Error while generating OTP: " + e.getMessage()); + } + } + + // Fallback to previously configured generic sendUrl behavior + if (sendUrl == null || sendUrl.isEmpty()) { + return new OtpSendResponse(true, "(stub) OTP sent to " + mobile); + } + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + Map body = new HashMap<>(); + body.put("mobile", mobile); + HttpEntity> req = new HttpEntity<>(body, headers); + // expecting external API returns {"success":true,"message":"..."} + Map resp = restTemplate.postForObject(sendUrl, req, Map.class); + boolean success = resp != null && Boolean.TRUE.equals(resp.get("success")); + String message = resp == null ? "no response" : String.valueOf(resp.get("message")); + return new OtpSendResponse(success, message); + } catch (Exception e) { + logger.error("Unexpected error in sendOtp: {}", e.getMessage(), e); + return new OtpSendResponse(false, "Failed to call OTP send: " + e.getMessage()); + } + } + + /** + * Calls external API to verify OTP. Returns true if OTP valid. + */ + public boolean verifyOtp(String mobile, String otp) { + try { + // basic input validation + if (mobile == null || mobile.isEmpty() || otp == null || otp.isEmpty()) { + logger.debug("verifyOtp called with empty mobile or otp"); + return false; + } + + logger.info("Verifying Mobile OTP for mobile: {}", mobile); + + // If an eKYC verify endpoint is configured, use it + if (verifyUrl != null && !verifyUrl.isEmpty()) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + + Map requestBody = new HashMap<>(); + requestBody.put("mobileNumber", mobile); + requestBody.put("apiKey", apiKey); + requestBody.put("secretKey", secretKey); + requestBody.put("otp", otp); + + HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); + try { + ResponseEntity response = restTemplate.exchange(verifyUrl, HttpMethod.POST, + requestEntity, String.class); + + logger.info("Mobile OTP verification API response: status={}, body={}", response.getStatusCode(), + response.getBody()); + + if (response.getStatusCode() == HttpStatus.OK) { + String respBody = response.getBody(); + if (respBody != null) { + // try to parse JSON and look for common verification keys + ObjectMapper mapper = new ObjectMapper(); + try { + Map respMap = mapper.readValue(respBody, Map.class); + if (respMap.containsKey("verified")) { + return Boolean.TRUE.equals(respMap.get("verified")); + } + if (respMap.containsKey("success")) { + return Boolean.TRUE.equals(respMap.get("success")); + } + if (respMap.containsKey("status") && "OK".equalsIgnoreCase(String.valueOf(respMap.get("status")))) { + return true; + } + } catch (Exception e) { + logger.debug("Unable to parse verification response body to JSON: {}", e.getMessage()); + // fall through to treat 200 as success + } + } + // fallback: treat HTTP 200 as successful verification + return true; + } else { + logger.warn("OTP verification endpoint returned non-OK status: {}", response.getStatusCode()); + return false; + } + } catch (Exception e) { + logger.error("Error calling eKYC OTP verify API: {}", e.getMessage(), e); + return false; + } + } + + // stub behaviour when no verify URL configured: accept OTP "123456" + return false; + } catch (Exception e) { + logger.error("Unexpected error in verifyOtp: {}", e.getMessage(), e); + return false; + } + } +} diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 17c421e..4eaafbc 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -20,12 +20,20 @@ swagger.server.description=Local Development Server # DataSource spring.datasource.url=jdbc:postgresql://localhost:5432/BBPS spring.datasource.username=postgres -spring.datasource.password=UAT@DB_2025 +#spring.datasource.password=UAT@DB_2025 -#spring.datasource.password=himanshu@123 +spring.datasource.password=himanshu@123 spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.type=com.zaxxer.hikari.HikariDataSource +ekyc.apikey=key_live_823fb2b5ba984ea293b6695331f83788 +ekyc.secreteKey= secret_live_b2acae6e1fd54d6faa148b08af8ae098 +ekyc.mobile=https://ekyc.lincpay.in/EKYC/ekyc/mobile/generate-otp +ekyc.mobile.verify.otp=https://ekyc.lincpay.in/EKYC/ekyc/verify-mobile-otp + + + +enc.key=lincpay # HikariCP settings spring.datasource.hikari.connection-timeout=10000 diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c652768..3d857c5 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -46,6 +46,12 @@ agent.data.url=https://bbps-staging.digiledge.in/agent/bill-payment-new payment.data.url=https://bbps-staging.digiledge.in/couapp complaint.data.url=https://bbps-staging.digiledge.in + +ekyc.apikey=key_live_823fb2b5ba984ea293b6695331f83788 +ekyc.secreteKey= secret_live_b2acae6e1fd54d6faa148b08af8ae098 +ekyc.mobile=https://ekyc.lincpay.in/EKYC/ekyc/mobile/generate-otp +ekyc.mobile.verify.otp=https://ekyc.lincpay.in/EKYC/ekyc/verify-mobile-otp + # throw NoHandlerFoundException for 404s spring.mvc.throw-exception-if-no-handler-found=true