diff --git a/src/main/java/zw/qantra/tm/domain/controllers/CategoryController.java b/src/main/java/zw/qantra/tm/domain/controllers/CategoryController.java index aa8cf57..a410a3c 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/CategoryController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/CategoryController.java @@ -9,7 +9,7 @@ import zw.qantra.tm.domain.services.CategoryService; import java.util.UUID; @RestController -@RequestMapping("/categories") +@RequestMapping("/public/categories") @RequiredArgsConstructor public class CategoryController { diff --git a/src/main/java/zw/qantra/tm/domain/controllers/ConfirmationController.java b/src/main/java/zw/qantra/tm/domain/controllers/ConfirmationController.java index 6f19563..528efa6 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/ConfirmationController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/ConfirmationController.java @@ -10,7 +10,7 @@ import zw.qantra.tm.domain.models.Transaction; import zw.qantra.tm.domain.services.TransactionService; @RestController -@RequestMapping("/confirm/transaction") +@RequestMapping("/public/confirm/transaction") @RequiredArgsConstructor public class ConfirmationController { private final TransactionService transactionService; diff --git a/src/main/java/zw/qantra/tm/domain/controllers/IntegrationController.java b/src/main/java/zw/qantra/tm/domain/controllers/IntegrationController.java index ce37cd9..eabff08 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/IntegrationController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/IntegrationController.java @@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController -@RequestMapping("/integration/transaction") +@RequestMapping("/public/integration/transaction") @RequiredArgsConstructor public class IntegrationController { @PostMapping() diff --git a/src/main/java/zw/qantra/tm/domain/controllers/PaymentProcessorController.java b/src/main/java/zw/qantra/tm/domain/controllers/PaymentProcessorController.java index 305edc5..c15afb8 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/PaymentProcessorController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/PaymentProcessorController.java @@ -11,7 +11,7 @@ import java.util.Optional; import java.util.UUID; @RestController -@RequestMapping("/payment-processors") +@RequestMapping("/public/payment-processors") @RequiredArgsConstructor public class PaymentProcessorController { diff --git a/src/main/java/zw/qantra/tm/domain/controllers/ProviderController.java b/src/main/java/zw/qantra/tm/domain/controllers/ProviderController.java index 829ff47..ad9334c 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/ProviderController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/ProviderController.java @@ -9,7 +9,7 @@ import zw.qantra.tm.domain.services.ProviderService; import java.util.UUID; @RestController -@RequestMapping("/providers") +@RequestMapping("/public/providers") @RequiredArgsConstructor public class ProviderController { diff --git a/src/main/java/zw/qantra/tm/domain/controllers/RecipientController.java b/src/main/java/zw/qantra/tm/domain/controllers/RecipientController.java index 13d7972..98e21a5 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/RecipientController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/RecipientController.java @@ -16,7 +16,7 @@ import java.util.List; import java.util.UUID; @RestController -@RequestMapping("/recipients") +@RequestMapping("/public/recipients") @RequiredArgsConstructor public class RecipientController { diff --git a/src/main/java/zw/qantra/tm/domain/controllers/TransactonController.java b/src/main/java/zw/qantra/tm/domain/controllers/TransactonController.java index 9150692..eb08453 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/TransactonController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/TransactonController.java @@ -2,7 +2,6 @@ package zw.qantra.tm.domain.controllers; import lombok.RequiredArgsConstructor; import net.kaczmarzyk.spring.data.jpa.domain.Equal; -import net.kaczmarzyk.spring.data.jpa.web.annotation.And; import net.kaczmarzyk.spring.data.jpa.web.annotation.Or; import net.kaczmarzyk.spring.data.jpa.web.annotation.Spec; import net.kaczmarzyk.spring.data.jpa.web.annotation.Conjunction; @@ -21,7 +20,7 @@ import zw.qantra.tm.utils.LogUtils; import java.util.UUID; @RestController -@RequestMapping("/transaction") +@RequestMapping("/public/transaction") @RequiredArgsConstructor public class TransactonController { Logger logger = LoggerFactory.getLogger(TransactonController.class); diff --git a/src/main/java/zw/qantra/tm/domain/enums/RequestType.java b/src/main/java/zw/qantra/tm/domain/enums/RequestType.java index 5338475..83bb54a 100644 --- a/src/main/java/zw/qantra/tm/domain/enums/RequestType.java +++ b/src/main/java/zw/qantra/tm/domain/enums/RequestType.java @@ -3,5 +3,6 @@ package zw.qantra.tm.domain.enums; public enum RequestType { CONFIRM, REQUEST, + POLL, INTEGRATION } diff --git a/src/main/java/zw/qantra/tm/domain/enums/Status.java b/src/main/java/zw/qantra/tm/domain/enums/Status.java index 324b27b..2709fc7 100755 --- a/src/main/java/zw/qantra/tm/domain/enums/Status.java +++ b/src/main/java/zw/qantra/tm/domain/enums/Status.java @@ -5,5 +5,8 @@ public enum Status { PENDING, FAILED, CANCELLED, - REVERSED + REVERSED, + AUTHORIZED, + REJECTED, + PROCESSING } diff --git a/src/main/java/zw/qantra/tm/domain/models/Transaction.java b/src/main/java/zw/qantra/tm/domain/models/Transaction.java index d240f21..6c0ec50 100644 --- a/src/main/java/zw/qantra/tm/domain/models/Transaction.java +++ b/src/main/java/zw/qantra/tm/domain/models/Transaction.java @@ -59,6 +59,19 @@ public class Transaction extends BaseEntity { private String providerImage; private String paymentProcessorImage; + @Enumerated(EnumType.STRING) + private Status authorizationStatus; + @Enumerated(EnumType.STRING) + private Status confirmationStatus; + @Enumerated(EnumType.STRING) + private Status paymentStatus; + @Enumerated(EnumType.STRING) + private Status integrationStatus; + @Enumerated(EnumType.STRING) + private Status reversalStatus; + @Enumerated(EnumType.STRING) + private Status pollingStatus; + private String erpSalesRef; private String erpJournalRef; private String erpSalesPaymentRef; diff --git a/src/main/java/zw/qantra/tm/domain/models/TransactionEvent.java b/src/main/java/zw/qantra/tm/domain/models/TransactionEvent.java new file mode 100644 index 0000000..92c6e22 --- /dev/null +++ b/src/main/java/zw/qantra/tm/domain/models/TransactionEvent.java @@ -0,0 +1,29 @@ +package zw.qantra.tm.domain.models; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import jakarta.persistence.Entity; +import jakarta.persistence.Enumerated; +import jakarta.persistence.EnumType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import zw.qantra.tm.domain.enums.Status; + +@Entity +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class TransactionEvent extends BaseEntity { + private String transactionId; + private String event; + @Enumerated(EnumType.STRING) + private Status status; + private String message; + private String data; +} diff --git a/src/main/java/zw/qantra/tm/domain/repositories/TransactionEventRepository.java b/src/main/java/zw/qantra/tm/domain/repositories/TransactionEventRepository.java new file mode 100644 index 0000000..3bfbd1c --- /dev/null +++ b/src/main/java/zw/qantra/tm/domain/repositories/TransactionEventRepository.java @@ -0,0 +1,10 @@ +package zw.qantra.tm.domain.repositories; + +import java.util.List; +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import zw.qantra.tm.domain.models.TransactionEvent; + +public interface TransactionEventRepository extends JpaRepository { + List findByTransactionId(UUID transactionId); +} diff --git a/src/main/java/zw/qantra/tm/domain/repositories/TransactionRepository.java b/src/main/java/zw/qantra/tm/domain/repositories/TransactionRepository.java index 653895c..3a4be35 100644 --- a/src/main/java/zw/qantra/tm/domain/repositories/TransactionRepository.java +++ b/src/main/java/zw/qantra/tm/domain/repositories/TransactionRepository.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Repository; import zw.qantra.tm.domain.enums.RequestType; import zw.qantra.tm.domain.models.Transaction; +import java.util.Optional; import java.util.UUID; @Repository diff --git a/src/main/java/zw/qantra/tm/domain/services/TransactionEventService.java b/src/main/java/zw/qantra/tm/domain/services/TransactionEventService.java new file mode 100644 index 0000000..077c4f7 --- /dev/null +++ b/src/main/java/zw/qantra/tm/domain/services/TransactionEventService.java @@ -0,0 +1,18 @@ +package zw.qantra.tm.domain.services; + +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; +import zw.qantra.tm.domain.models.TransactionEvent; +import zw.qantra.tm.domain.repositories.TransactionEventRepository; + +@Service +@RequiredArgsConstructor +public class TransactionEventService { + private final TransactionEventRepository transactionEventRepository; + + public void save(TransactionEvent transactionEvent) { + transactionEventRepository.save(transactionEvent); + } + +} diff --git a/src/main/java/zw/qantra/tm/domain/services/TransactionService.java b/src/main/java/zw/qantra/tm/domain/services/TransactionService.java index 480808e..6fcd32d 100644 --- a/src/main/java/zw/qantra/tm/domain/services/TransactionService.java +++ b/src/main/java/zw/qantra/tm/domain/services/TransactionService.java @@ -30,6 +30,8 @@ import zw.qantra.tm.domain.services.processors.handlers.RecipientsUpdateHandler; import zw.qantra.tm.domain.services.processors.handlers.ValidationHandler; import zw.qantra.tm.domain.services.processors.handlers.erp.PurchaseInvoiceHandler; import zw.qantra.tm.domain.services.processors.handlers.erp.SalesInvoiceHandler; +import zw.qantra.tm.domain.models.TransactionEvent; +import zw.qantra.tm.domain.services.TransactionEventService; import zw.qantra.tm.exceptions.ApiException; import zw.qantra.tm.utils.Utils; @@ -45,10 +47,18 @@ public class TransactionService { private final ChargeService chargeService; private final AdditionalDataService additionalDataService; private final RecipientService recipientService; + private final TransactionEventService transactionEventService; public Transaction integration(Transaction transaction) { transaction.setType(RequestType.INTEGRATION); + TransactionEvent transactionEvent = TransactionEvent.builder() + .transactionId(transaction.getId().toString()) + .event(transaction.getType().name()) + .status(Status.PROCESSING) + .build(); + transactionEventService.save(transactionEvent); + LogicPipeline transactionLogic = new LogicPipeline<>(new ValidationHandler()); transaction = transactionLogic.execute(transaction); @@ -81,6 +91,10 @@ public class TransactionService { LogicPipeline postTransactionLogic = new LogicPipeline<>(new PurchaseInvoiceHandler()); transaction = postTransactionLogic.execute(transaction); + + transactionEvent.setStatus(transaction.getStatus()); + transactionEvent.setMessage(transaction.getErrorMessage()); + transactionEventService.save(transactionEvent); return transaction; } @@ -96,6 +110,13 @@ public class TransactionService { return transaction; } + TransactionEvent transactionEvent = TransactionEvent.builder() + .transactionId(transaction.getId().toString()) + .event(RequestType.POLL.name()) + .status(Status.PROCESSING) + .build(); + transactionEventService.save(transactionEvent); + // no persistence happens during polling unless the transaction status changes String label = getLabel(transaction); logger.info("label: {}", label); @@ -106,12 +127,14 @@ public class TransactionService { // find out if the gateway tran was successful transactionProcessorInterface.poll(transaction); - // if tran was successful deep copy transaction & push integration to the aggregator + transactionEvent.setStatus(transaction.getStatus()); + transactionEvent.setMessage(transaction.getErrorMessage()); + transactionEventService.save(transactionEvent); + + // if tran was successful push integration to the aggregator if(transaction.getStatus() == Status.SUCCESS){ - Transaction transactionCopy = Utils.deepCopy(transaction, Transaction.class); - transactionCopy.setType(RequestType.INTEGRATION); - transactionCopy.setId(null); - integration(transactionCopy); + transaction.setType(RequestType.INTEGRATION); + integration(transaction); } } catch (Exception e) { e.printStackTrace(); @@ -119,11 +142,25 @@ public class TransactionService { transaction.setResponseCode("01"); transaction.setErrorMessage(e.getMessage()); } + return transaction; } - public Transaction execute(Transaction transaction) { - transaction.setReference(UUID.randomUUID().toString()); + public Transaction execute(Transaction incomingTransaction) { + // if payment request (not confirm), then fetch already existing transaction record + Transaction transaction = incomingTransaction; + if(incomingTransaction.getId() != null){ + transaction = getTransactionRepository().findById(incomingTransaction.getId()).orElseThrow(() -> + new ApiException("Transaction not found for ID: " + incomingTransaction.getId())); + transaction.setType(incomingTransaction.getType()); // type should be REQUEST here + } + + TransactionEvent transactionEvent = TransactionEvent.builder() + .transactionId(transaction.getId().toString()) + .event(transaction.getType().name()) + .status(Status.PROCESSING) + .build(); + transactionEventService.save(transactionEvent); // run pre transaction logic LogicPipeline preTransactionLogic = @@ -143,6 +180,12 @@ public class TransactionService { // MAIN TRANSACTION LOGIC! transactionProcessorInterface.process(transaction); + if(transaction.getType() == RequestType.CONFIRM){ + transaction.setConfirmationStatus(transaction.getStatus()); + }else{ + transaction.setPaymentStatus(transaction.getStatus()); + } + }catch (Exception e){ e.printStackTrace(); transaction.setStatus(Status.FAILED); @@ -158,13 +201,16 @@ public class TransactionService { .addHandler(new SalesInvoiceHandler()); transaction = postTransactionLogic.execute(transaction); + transactionEvent.setStatus(transaction.getStatus()); + transactionEvent.setMessage(transaction.getErrorMessage()); + transactionEventService.save(transactionEvent); + return transaction; } private String getLabel(Transaction transaction){ String label = ""; - List list = Arrays.asList(RequestType.CONFIRM); - if(list.contains(transaction.getType())){ + if(transaction.getType() == RequestType.CONFIRM){ // get processor label from billClientId Provider provider = providerService.getProviderRepository() .findByClientId(transaction.getBillClientId()); @@ -173,6 +219,8 @@ public class TransactionService { } label = transaction.getType() + "_" + provider.getLabel(); + + transaction.setIntegrationProcessorLabel(provider.getIntegrationProcessorLabel()); }else{ label = transaction.getType() + "_" + transaction.getPaymentProcessorLabel() + "_" + diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/handlers/ConfirmationLogicHandler.java b/src/main/java/zw/qantra/tm/domain/services/processors/handlers/ConfirmationLogicHandler.java index 43a448c..c537d7a 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/handlers/ConfirmationLogicHandler.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/handlers/ConfirmationLogicHandler.java @@ -1,5 +1,7 @@ package zw.qantra.tm.domain.services.processors.handlers; +import java.util.UUID; + import zw.qantra.tm.domain.enums.RequestType; import zw.qantra.tm.domain.models.Transaction; import zw.qantra.tm.utils.Utils; @@ -9,6 +11,7 @@ public class ConfirmationLogicHandler implements LogicHandler