From 6f9505576129926159ccb8d13c8f6213d8bf2287 Mon Sep 17 00:00:00 2001 From: Raja Nabeel Date: Wed, 17 Apr 2024 12:13:17 +0500 Subject: [PATCH] commit create and verify tranpin --- pom.xml | 4 ++ src/main/java/com/mfsys/uco/UCOURI.java | 2 + .../uco/config/WebClientconfiguration.java | 18 +++++ .../mfsys/uco/controller/UserController.java | 29 +++++++- .../uco/dto/CreateTransactionPinRequest.java | 21 ++++++ .../java/com/mfsys/uco/dto/OTPRequest.java | 21 ++++++ .../com/mfsys/uco/dto/VerifyPinRequest.java | 22 +++++++ .../com/mfsys/uco/model/CustomerProfile.java | 18 +++-- .../mfsys/uco/model/CustomerProfileId.java | 66 +++++++++++++++++++ src/main/java/com/mfsys/uco/model/Pin.java | 64 ++++++++++++++++++ .../repository/CustomerProfileRepository.java | 10 +++ .../mfsys/uco/repository/PinRepository.java | 15 +++++ .../uco/service/NotificationService.java | 63 ++++++++++++++++++ .../uco/service/TransactionPinService.java | 53 +++++++++++++++ 14 files changed, 401 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/mfsys/uco/config/WebClientconfiguration.java create mode 100644 src/main/java/com/mfsys/uco/dto/CreateTransactionPinRequest.java create mode 100644 src/main/java/com/mfsys/uco/dto/OTPRequest.java create mode 100644 src/main/java/com/mfsys/uco/dto/VerifyPinRequest.java create mode 100644 src/main/java/com/mfsys/uco/model/CustomerProfileId.java create mode 100644 src/main/java/com/mfsys/uco/model/Pin.java create mode 100644 src/main/java/com/mfsys/uco/repository/CustomerProfileRepository.java create mode 100644 src/main/java/com/mfsys/uco/repository/PinRepository.java create mode 100644 src/main/java/com/mfsys/uco/service/NotificationService.java create mode 100644 src/main/java/com/mfsys/uco/service/TransactionPinService.java diff --git a/pom.xml b/pom.xml index c30fa20..bb43cee 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-webflux + com.itextpdf itext7-core diff --git a/src/main/java/com/mfsys/uco/UCOURI.java b/src/main/java/com/mfsys/uco/UCOURI.java index c2ab879..262c3e0 100644 --- a/src/main/java/com/mfsys/uco/UCOURI.java +++ b/src/main/java/com/mfsys/uco/UCOURI.java @@ -8,4 +8,6 @@ public interface UCOURI { String GET_TRANSACTION_PIN = "/transactionPin"; String SUBMIT_TRANSACTION = "/submitTransaction"; String GENERATE_TRANSACTIONS_REPORT = "/generateReport"; + String CREATE_TRAN_PIN = "/createTransactionPin"; + String VERIFY_TRAN_PIN = "/verifyTransactionPin"; } diff --git a/src/main/java/com/mfsys/uco/config/WebClientconfiguration.java b/src/main/java/com/mfsys/uco/config/WebClientconfiguration.java new file mode 100644 index 0000000..121999d --- /dev/null +++ b/src/main/java/com/mfsys/uco/config/WebClientconfiguration.java @@ -0,0 +1,18 @@ +package com.mfsys.uco.config; + +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientconfiguration { + + @LoadBalanced + @Bean + public WebClient.Builder loadBalancedWebClientBuilder() { + return WebClient.builder(); + } +} + + diff --git a/src/main/java/com/mfsys/uco/controller/UserController.java b/src/main/java/com/mfsys/uco/controller/UserController.java index dfd9f1f..d7e26c8 100644 --- a/src/main/java/com/mfsys/uco/controller/UserController.java +++ b/src/main/java/com/mfsys/uco/controller/UserController.java @@ -6,7 +6,10 @@ import com.itextpdf.layout.Document; import com.itextpdf.layout.element.Paragraph; import com.mfsys.uco.UCOURI; import com.mfsys.uco.dto.*; +import com.mfsys.uco.service.TransactionPinService; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.io.ByteArrayOutputStream; @@ -18,6 +21,9 @@ import java.util.List; @RestController @RequiredArgsConstructor public class UserController { + + private final TransactionPinService transactionPinService; + @PostMapping(UCOURI.VIEW_BALANCE) public ViewBalanceResponseModel viewBalance(@RequestBody ViewBalanceRequestModel viewBalanceRequestModel) { ViewBalanceResponseModel viewBalanceResponseModel = new ViewBalanceResponseModel(); @@ -107,6 +113,27 @@ public class UserController { return "Error generating report"; } } + @PostMapping(UCOURI.CREATE_TRAN_PIN) + public ResponseEntity createTransactionPin(@RequestBody CreateTransactionPinRequest request) { + try { + transactionPinService.createTransactionPin(request); + return ResponseEntity.ok(HttpStatus.OK); + } catch (Exception e) { + return ResponseEntity.ok(HttpStatus.INTERNAL_SERVER_ERROR); + } + } - + @PostMapping(UCOURI.VERIFY_TRAN_PIN) + public ResponseEntity verifyPin(@RequestBody VerifyPinRequest request) { + try { + boolean isVerified = transactionPinService.verifyOTPAndSavePin(request); + if (isVerified) { + return ResponseEntity.ok("PIN verified successfully."); + } else { + return ResponseEntity.badRequest().body("PIN verification failed."); + } + } catch (Exception e) { + return ResponseEntity.status(500).body("Error during PIN verification: " + e.getMessage()); + } + } } diff --git a/src/main/java/com/mfsys/uco/dto/CreateTransactionPinRequest.java b/src/main/java/com/mfsys/uco/dto/CreateTransactionPinRequest.java new file mode 100644 index 0000000..ff517c9 --- /dev/null +++ b/src/main/java/com/mfsys/uco/dto/CreateTransactionPinRequest.java @@ -0,0 +1,21 @@ +package com.mfsys.uco.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CreateTransactionPinRequest { + private String newTransPincode; + private String channelCode; + private String pctCstycode; + private String porOrgacode; + private String cmpCustcode; + private boolean isOtpRequired; +} + + diff --git a/src/main/java/com/mfsys/uco/dto/OTPRequest.java b/src/main/java/com/mfsys/uco/dto/OTPRequest.java new file mode 100644 index 0000000..5bd06af --- /dev/null +++ b/src/main/java/com/mfsys/uco/dto/OTPRequest.java @@ -0,0 +1,21 @@ +package com.mfsys.uco.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class OTPRequest { + private boolean isOtpRequired; + private String email; + private String phone; + private String channelCode; + private String porOrgacode; + private String username; + private String pinType; + private String subject; +} diff --git a/src/main/java/com/mfsys/uco/dto/VerifyPinRequest.java b/src/main/java/com/mfsys/uco/dto/VerifyPinRequest.java new file mode 100644 index 0000000..49d8211 --- /dev/null +++ b/src/main/java/com/mfsys/uco/dto/VerifyPinRequest.java @@ -0,0 +1,22 @@ +package com.mfsys.uco.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class VerifyPinRequest { + String channelCode; + String pctCstycode; + String porOrgacode; + String cmpCustcode; + String email; + String obpPincode; + String pinType; +} + + diff --git a/src/main/java/com/mfsys/uco/model/CustomerProfile.java b/src/main/java/com/mfsys/uco/model/CustomerProfile.java index f4fc29d..e355a10 100644 --- a/src/main/java/com/mfsys/uco/model/CustomerProfile.java +++ b/src/main/java/com/mfsys/uco/model/CustomerProfile.java @@ -1,10 +1,7 @@ package com.mfsys.uco.model; import com.mfsys.comm.util.FieldNameLength; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -16,6 +13,7 @@ import java.time.LocalDate; @Table(name = "BN_CS_MP_CUSTOMERPROFILE") @Data @Builder +@IdClass(CustomerProfileId.class) @AllArgsConstructor @NoArgsConstructor public class CustomerProfile { @@ -30,6 +28,7 @@ public class CustomerProfile { @Column(name = "PIT_IDENVALUE", nullable = true, columnDefinition = FieldNameLength.CODE_20) protected String pitIdenvalue; + @Column(name = "PIT_IDENCODE", nullable = true, columnDefinition = FieldNameLength.CODE_20) protected String pitIdencode; @@ -39,10 +38,21 @@ public class CustomerProfile { @Column(name = "KYC_RENEWAL_DATE", nullable = true, columnDefinition = FieldNameLength.DATE) protected LocalDate kycRenewalDate; + @Column(name = "CMP_EMAIL", nullable = true, columnDefinition = FieldNameLength.CODE_50) + private String cmpEmail; + @Column(name = "CMP_NAME", nullable = true, columnDefinition = FieldNameLength.CODE_50) private String cmpName; + @Column(name = "CMP_USERNAME", nullable = true, columnDefinition = FieldNameLength.CODE_50) + private String cmpUserName; + @Column(name = "CMP_ISKYC_VERIFIED", nullable=false, columnDefinition=FieldNameLength.BOOLEAN_BIT) protected boolean cmpIsKycVerified = false; + @Column(name = "CMP_TRAN_PIN", nullable=false, columnDefinition=FieldNameLength.PIN_VALUE) + protected String cmpTranpin; + + @Column(name = "CMP_TRAN_PIN_VERIFIED", nullable=false, columnDefinition=FieldNameLength.BOOLEAN_BIT) + protected boolean cmpTranpinVerfied = false; } diff --git a/src/main/java/com/mfsys/uco/model/CustomerProfileId.java b/src/main/java/com/mfsys/uco/model/CustomerProfileId.java new file mode 100644 index 0000000..e14213e --- /dev/null +++ b/src/main/java/com/mfsys/uco/model/CustomerProfileId.java @@ -0,0 +1,66 @@ +package com.mfsys.uco.model; + +import java.io.Serializable; + +public class CustomerProfileId implements Serializable { + + private static final long serialVersionUID = 1L; + + private String porOrgacode; + private String cmpCustcode; + + public String getPorOrgacode() { + return porOrgacode; + } + + public void setPorOrgacode(String porOrgacode) { + this.porOrgacode = porOrgacode; + } + + public String getCmpCustcode() { + return cmpCustcode; + } + + public void setCmpCustcode(String cmpCustcode) { + this.cmpCustcode = cmpCustcode; + } + + public CustomerProfileId() { + } + + public CustomerProfileId(String porOrgacode, String cmpCustcode) { + this.porOrgacode = porOrgacode; + this.cmpCustcode = cmpCustcode; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((cmpCustcode == null) ? 0 : cmpCustcode.hashCode()); + result = prime * result + ((porOrgacode == null) ? 0 : porOrgacode.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CustomerProfileId other = (CustomerProfileId) obj; + if (cmpCustcode == null) { + if (other.cmpCustcode != null) + return false; + } else if (!cmpCustcode.equals(other.cmpCustcode)) + return false; + if (porOrgacode == null) { + if (other.porOrgacode != null) + return false; + } else if (!porOrgacode.equals(other.porOrgacode)) + return false; + return true; + } +} diff --git a/src/main/java/com/mfsys/uco/model/Pin.java b/src/main/java/com/mfsys/uco/model/Pin.java new file mode 100644 index 0000000..e6fd970 --- /dev/null +++ b/src/main/java/com/mfsys/uco/model/Pin.java @@ -0,0 +1,64 @@ +package com.mfsys.uco.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.mfsys.comm.util.FieldNameLength; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import java.time.LocalDateTime; + +@Entity(name = "DG_PN_PIN") +@Table(name = "DG_PN_PIN") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class Pin { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "PINSERIAL", nullable = false, updatable = false, columnDefinition = FieldNameLength.BIGINT) + private Long pinserial; + + @Column(name = "POR_ORGACODE", nullable = false, updatable = false, columnDefinition = FieldNameLength.POR_ORGACODE) + private String porOrgacode; + + @Column(name = "username", nullable = false, updatable = false, columnDefinition = FieldNameLength.USER_NAME) + private String userName; + + @Column(name = "CHANNEL_CODE", nullable = false, updatable = false, columnDefinition = FieldNameLength.CHANNEL_CODE) + private String channelCode; + + @Column(name = "PINTYPE", nullable = false, updatable = false, columnDefinition = FieldNameLength.CODE_10) + private String pintype; + + @Column(name = "PINLENGTH", nullable = false, updatable = false, columnDefinition = FieldNameLength.PIN_LENGTH) + private int pinlength; + + @Column(name = "PINCODE", nullable = false, updatable = true, columnDefinition = FieldNameLength.PIN_VALUE) + private String pincode; + + @Column(name = "PIN_CREATEDATE", nullable = false, updatable = true, columnDefinition = FieldNameLength.DATETIME) + private LocalDateTime pinCreatedate; + + @Column(name = "PIN_EXPIRYDATE", nullable = false, updatable = true, columnDefinition = FieldNameLength.DATETIME) + private LocalDateTime pinExpirydate; + + @Column(name = "PINSTATUS", nullable = false, updatable = true, columnDefinition = FieldNameLength.CODE_20) + private String pinstatus; + + @Column(name = "PIN_VALIDATIONDATE", nullable = true, updatable = true, columnDefinition = FieldNameLength.DATETIME) + private LocalDateTime pinValidationdate; + + @JsonIgnore + @Column(name = "Version", nullable = false, updatable = true, columnDefinition = FieldNameLength.INT) + @Version + private int version; + +} diff --git a/src/main/java/com/mfsys/uco/repository/CustomerProfileRepository.java b/src/main/java/com/mfsys/uco/repository/CustomerProfileRepository.java new file mode 100644 index 0000000..e3ff526 --- /dev/null +++ b/src/main/java/com/mfsys/uco/repository/CustomerProfileRepository.java @@ -0,0 +1,10 @@ +package com.mfsys.uco.repository; + +import com.mfsys.uco.model.CustomerProfile; +import com.mfsys.uco.model.CustomerProfileId; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CustomerProfileRepository extends JpaRepository { +} diff --git a/src/main/java/com/mfsys/uco/repository/PinRepository.java b/src/main/java/com/mfsys/uco/repository/PinRepository.java new file mode 100644 index 0000000..43b85f8 --- /dev/null +++ b/src/main/java/com/mfsys/uco/repository/PinRepository.java @@ -0,0 +1,15 @@ +package com.mfsys.uco.repository; + +import com.mfsys.uco.model.Pin; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface PinRepository extends JpaRepository { + @Query("SELECT p FROM DG_PN_PIN p WHERE p.userName = :username AND p.pinstatus = 'Unverified' AND p.pinExpirydate > CURRENT_TIMESTAMP ORDER BY p.pinserial DESC LIMIT 1") + Optional findLatestActiveOtpByUserName(String username); + +} diff --git a/src/main/java/com/mfsys/uco/service/NotificationService.java b/src/main/java/com/mfsys/uco/service/NotificationService.java new file mode 100644 index 0000000..692007a --- /dev/null +++ b/src/main/java/com/mfsys/uco/service/NotificationService.java @@ -0,0 +1,63 @@ +package com.mfsys.uco.service; + +import com.mfsys.comm.commonservices.OtpService; +import com.mfsys.comm.constant.EurekaRegisteredMicroServicesURI; +import com.mfsys.comm.exception.InvalidOTPException; +import com.mfsys.uco.dto.OTPRequest; +import com.mfsys.uco.model.Pin; +import com.mfsys.uco.repository.PinRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Optional; + +@Component +public class NotificationService { + @LoadBalanced + private final WebClient webClient; + private final OtpService otpService; + private final PinRepository pinRepository; + + public NotificationService(WebClient.Builder webClientBuilder, OtpService otpService, PinRepository pinRepository) { + this.webClient = webClientBuilder.baseUrl(EurekaRegisteredMicroServicesURI.NOTIFICATION_SERVICE_LB).build(); + this.otpService = otpService; + this.pinRepository = pinRepository; + } + + public Mono sendOtp(OTPRequest otpRequest) { + String otp = otpRequest.isOtpRequired() ? otpService.generateOtp() : "123456"; + Pin pin = new Pin(); + final LocalDateTime createDate = LocalDateTime.now(); + final LocalDateTime expiryDate = LocalDateTime.now().plusMinutes(5); + pin.setPinCreatedate(createDate); + pin.setPinExpirydate(expiryDate); + pin.setChannelCode(otpRequest.getChannelCode()); + pin.setPintype(otpRequest.getPinType()); + pin.setPincode(otp); + pin.setPorOrgacode(otpRequest.getPorOrgacode()); + pin.setVersion(1); + pin.setPinlength(6); + pin.setPinstatus("Unverified"); + pin.setUserName(otpRequest.getEmail()); + pinRepository.save(pin); + webClient.post().uri("/notification/otp/email").bodyValue(Map.of("email", otpRequest.getEmail(), "subject", otpRequest.getSubject(), "otp", otp, "userName", otpRequest.getUsername())).retrieve() + .onStatus(status -> status.is4xxClientError() || status.is5xxServerError(), clientResponse + -> Mono.error(new RuntimeException("Response has error status."))).bodyToMono(String.class).block(); + return null; + } + + public void verifyOtp(String porOrgacode, String email, String obpPincode) { + Optional pin = pinRepository.findLatestActiveOtpByUserName(email); + if (pin.isPresent() && pin.get().getPincode().equals(obpPincode) && pin.get().getPorOrgacode().equals(porOrgacode)) { + pin.get().setPinstatus("VERIFIED"); + pinRepository.save(pin.get()); + return; + } + throw new InvalidOTPException(porOrgacode); + } +} diff --git a/src/main/java/com/mfsys/uco/service/TransactionPinService.java b/src/main/java/com/mfsys/uco/service/TransactionPinService.java new file mode 100644 index 0000000..5c60a64 --- /dev/null +++ b/src/main/java/com/mfsys/uco/service/TransactionPinService.java @@ -0,0 +1,53 @@ +package com.mfsys.uco.service; + +import com.mfsys.uco.dto.CreateTransactionPinRequest; +import com.mfsys.uco.dto.OTPRequest; +import com.mfsys.uco.dto.VerifyPinRequest; +import com.mfsys.uco.model.CustomerProfile; +import com.mfsys.uco.model.CustomerProfileId; +import com.mfsys.uco.repository.CustomerProfileRepository; +import com.mfsys.uco.repository.PinRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class TransactionPinService { + + private final CustomerProfileRepository customerProfileRepository; + private final NotificationService notificationService; + + public void createTransactionPin(CreateTransactionPinRequest request) { + CustomerProfile profile = fetchCustomer(request.getPorOrgacode(), request.getCmpCustcode()); + OTPRequest otpRequest = OTPRequest.builder() + .porOrgacode(request.getPorOrgacode()) + .channelCode(request.getChannelCode()) + .pinType("C_PIN") + .email(profile.getCmpEmail()) + .phone(profile.getPadAdrsmobphone()) + .isOtpRequired(request.isOtpRequired()) + .username(profile.getCmpUserName()) + .subject("Create Transaction Pin Verification OTP") + .build(); + + notificationService.sendOtp(otpRequest); + customerProfileRepository.save(profile); + } + + + public boolean verifyOTPAndSavePin(VerifyPinRequest request) { + notificationService.verifyOtp(request.getPorOrgacode(), request.getEmail(), request.getObpPincode()); + CustomerProfile profile = fetchCustomer(request.getPorOrgacode(), request.getCmpCustcode()); + profile.setCmpTranpinVerfied(true); + customerProfileRepository.save(profile); + return true; + } + + public CustomerProfile fetchCustomer(String porOrgacode, String cmpCustcode){ + CustomerProfileId profileId = new CustomerProfileId(porOrgacode,cmpCustcode); + return customerProfileRepository.findById(profileId) + .orElseThrow(() -> new IllegalArgumentException("Customer profile not found for ID: " + profileId)); + } +}