completed initial scaffolding for services
This commit is contained in:
@@ -6,13 +6,17 @@ 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 zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.TransactionService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/confirm/transaction")
|
||||
@RequiredArgsConstructor
|
||||
public class ConfirmationController {
|
||||
private final TransactionService transactionService;
|
||||
|
||||
@PostMapping()
|
||||
public ResponseEntity post(@RequestBody Object transactionRequest) {
|
||||
return ResponseEntity.ok("Transaction endpoint is working");
|
||||
public ResponseEntity post(@RequestBody Transaction transaction) {
|
||||
return ResponseEntity.ok(transactionService.execute(transaction));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package zw.qantra.tm.domain.enums;
|
||||
|
||||
public enum ChargeConditionType {
|
||||
PROVIDER, // bill provider conditions
|
||||
GATEWAY, // payment gateway conditions
|
||||
TRANSACTION // qantra conditions
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package zw.qantra.tm.domain.enums;
|
||||
|
||||
public enum ChargeLabelEnum {
|
||||
FEE,
|
||||
TAX,
|
||||
GATEWAY_FEE
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package zw.qantra.tm.domain.enums;
|
||||
|
||||
public enum CurrencyType {
|
||||
ZWL,
|
||||
ZWG,
|
||||
USD,
|
||||
ZiG,
|
||||
ZAR
|
||||
}
|
||||
9
src/main/java/zw/qantra/tm/domain/enums/Status.java
Executable file
9
src/main/java/zw/qantra/tm/domain/enums/Status.java
Executable file
@@ -0,0 +1,9 @@
|
||||
package zw.qantra.tm.domain.enums;
|
||||
|
||||
public enum Status {
|
||||
SUCCESS,
|
||||
PENDING,
|
||||
FAILED,
|
||||
CANCELLED,
|
||||
REVERSED
|
||||
}
|
||||
6
src/main/java/zw/qantra/tm/domain/enums/TargetEvent.java
Normal file
6
src/main/java/zw/qantra/tm/domain/enums/TargetEvent.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package zw.qantra.tm.domain.enums;
|
||||
|
||||
public enum TargetEvent {
|
||||
INCLUDE,
|
||||
EXCLUDE
|
||||
}
|
||||
67
src/main/java/zw/qantra/tm/domain/models/Charge.java
Normal file
67
src/main/java/zw/qantra/tm/domain/models/Charge.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package zw.qantra.tm.domain.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
import zw.qantra.tm.domain.enums.ChargeLabelEnum;
|
||||
import zw.qantra.tm.domain.enums.CurrencyType;
|
||||
import zw.qantra.tm.domain.enums.TargetEvent;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Charge {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
private String description;
|
||||
|
||||
// % rate to charge
|
||||
private BigDecimal percentageRate;
|
||||
private BigDecimal flat;
|
||||
private boolean composite; // composite is % plus flat
|
||||
private boolean global;
|
||||
|
||||
private BigDecimal min;
|
||||
private BigDecimal max;
|
||||
private BigDecimal minimumAmount;
|
||||
private BigDecimal maximumAmount;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ChargeLabelEnum chargeLabel;
|
||||
@Enumerated(EnumType.STRING)
|
||||
private CurrencyType currency;
|
||||
private String account;
|
||||
private String target;
|
||||
private String targetValue;
|
||||
@Enumerated(EnumType.STRING)
|
||||
private TargetEvent targetEvent; // include / exclude
|
||||
|
||||
@JsonIgnore
|
||||
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "charge_include_products",
|
||||
joinColumns = @JoinColumn(name = "charge_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "charge_condition_id")
|
||||
)
|
||||
private Set<ChargeCondition> includes = new HashSet<>();
|
||||
|
||||
@JsonIgnore
|
||||
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "charge_exclude_products",
|
||||
joinColumns = @JoinColumn(name = "charge_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "charge_condition_id")
|
||||
)
|
||||
private Set<ChargeCondition> excludes = new HashSet<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package zw.qantra.tm.domain.models;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
import zw.qantra.tm.domain.enums.ChargeConditionType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ChargeCondition {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
private String name;
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ChargeConditionType type;
|
||||
@Column(columnDefinition = "longtext")
|
||||
private String codes;
|
||||
|
||||
@ManyToMany(mappedBy = "includes")
|
||||
List<Charge> includeCharges;
|
||||
@ManyToMany(mappedBy = "excludes")
|
||||
List<Charge> excludeCharges;
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package zw.qantra.tm.domain.models;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.*;
|
||||
import zw.qantra.tm.domain.enums.RequestType;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ConfirmTransaction {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
private String trace;
|
||||
private BigDecimal amount;
|
||||
private String reference;
|
||||
private String providerUid;
|
||||
private String productUid;
|
||||
private String paymentProcessorLabel;
|
||||
private String integrationProcessorLabel;
|
||||
private String rrn;
|
||||
private String channelName;
|
||||
private String channel;
|
||||
private String debitPhone;
|
||||
private String debitAccount;
|
||||
private String debitCurrency;
|
||||
private String debitName;
|
||||
private String debitCard;
|
||||
private String debitRef;
|
||||
private String creditPhone;
|
||||
private String creditAccount;
|
||||
private String creditCurrency;
|
||||
private String creditName;
|
||||
private String creditCard;
|
||||
private String creditRef;
|
||||
private String billClientId;
|
||||
private String clientSecret;
|
||||
private String aggregatorId;
|
||||
private String billName;
|
||||
private String billProductName;
|
||||
private RequestType type;
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
package zw.qantra.tm.domain.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
import zw.qantra.tm.domain.enums.CurrencyType;
|
||||
import zw.qantra.tm.domain.enums.RequestType;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@@ -13,6 +17,7 @@ import java.util.UUID;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Transaction {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
@@ -20,6 +25,10 @@ public class Transaction {
|
||||
|
||||
private String trace;
|
||||
private BigDecimal amount;
|
||||
private BigDecimal charge;
|
||||
private BigDecimal gatewayCharge;
|
||||
private BigDecimal tax;
|
||||
private BigDecimal totalAmount;
|
||||
private String reference;
|
||||
private String providerUid;
|
||||
private String productUid;
|
||||
@@ -30,13 +39,13 @@ public class Transaction {
|
||||
private String channel;
|
||||
private String debitPhone;
|
||||
private String debitAccount;
|
||||
private String debitCurrency;
|
||||
private CurrencyType debitCurrency;
|
||||
private String debitName;
|
||||
private String debitCard;
|
||||
private String debitRef;
|
||||
private String creditPhone;
|
||||
private String creditAccount;
|
||||
private String creditCurrency;
|
||||
private CurrencyType creditCurrency;
|
||||
private String creditName;
|
||||
private String creditCard;
|
||||
private String creditRef;
|
||||
@@ -46,4 +55,11 @@ public class Transaction {
|
||||
private String billName;
|
||||
private String billProductName;
|
||||
private RequestType type;
|
||||
|
||||
private String errorMessage;
|
||||
private String responseCode;
|
||||
private Status status;
|
||||
@Transient
|
||||
private List<Object> additionalData;
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package zw.qantra.tm.domain.repositories;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import zw.qantra.tm.domain.models.ConfirmTransaction;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface ConfirmTransactionRepository extends JpaRepository<ConfirmTransaction, UUID> {
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package zw.qantra.tm.domain.services;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.repositories.ConfirmTransactionRepository;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ConfirmTransactionService {
|
||||
private final ConfirmTransactionRepository confirmTransactionRepository;
|
||||
}
|
||||
@@ -2,10 +2,15 @@ package zw.qantra.tm.domain.services;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.PaymentProcessor;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.repositories.TransactionRepository;
|
||||
import zw.qantra.tm.domain.services.factories.PaymentProcessorFactory;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.CalculateChargesHandler;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.LogicPipeline;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.ValidationHandler;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -13,9 +18,26 @@ public class TransactionService {
|
||||
private final TransactionRepository transactionRepository;
|
||||
private final PaymentProcessorFactory paymentProcessorFactory;
|
||||
|
||||
private Transaction bootstrap(Transaction transaction) {
|
||||
String label = transaction.getType() + "_" + transaction.getPaymentProcessorLabel();
|
||||
// PaymentProcessor paymentProcessor = paymentProcessorFactory.getPaymentProcessor(label);
|
||||
public Transaction execute(Transaction transaction) {
|
||||
LogicPipeline<Transaction, Transaction> transactionLogic =
|
||||
new LogicPipeline<>(new CalculateChargesHandler())
|
||||
.addHandler(new ValidationHandler());
|
||||
transaction = transactionLogic.execute(transaction);
|
||||
|
||||
String label = transaction.getType() + "_" + transaction.getIntegrationProcessorLabel();
|
||||
TransactionProcessorInterface transactionProcessorInterface =
|
||||
(TransactionProcessorInterface) paymentProcessorFactory.getPaymentProcessor(label);
|
||||
|
||||
try {
|
||||
transactionProcessorInterface.process(transaction);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("01");
|
||||
transaction.setErrorMessage(e.getMessage());
|
||||
transactionRepository.save(transaction);
|
||||
return transaction;
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
import zw.qantra.tm.exceptions.ApiException;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@@ -28,11 +29,13 @@ public class PaymentProcessorFactory implements ApplicationContextAware {
|
||||
try {
|
||||
paymentProcessor = applicationContext.getBean(paymentProcessorName);
|
||||
} catch (NoSuchBeanDefinitionException exception) {
|
||||
exception.printStackTrace();
|
||||
logger.error("Couldn't find payment processor: {}", exception.getMessage());
|
||||
return null;
|
||||
throw new ApiException("Couldn't find payment processor");
|
||||
} catch (BeansException e) {
|
||||
e.printStackTrace();
|
||||
logger.error("Error retrieving payment processor bean: {}", e.getMessage());
|
||||
return null;
|
||||
throw new ApiException("Error retrieving payment processor bean");
|
||||
}
|
||||
|
||||
return paymentProcessor;
|
||||
|
||||
@@ -3,6 +3,6 @@ package zw.qantra.tm.domain.services.processors;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
|
||||
public interface TransactionProcessorInterface {
|
||||
Object process(Transaction transaction);
|
||||
Object process(Transaction transaction) throws Exception;
|
||||
Object reverse(Transaction transaction);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
package zw.qantra.tm.domain.services.processors.confirmations;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
|
||||
@Service("CONFIRM_POWERTEL_ZESA")
|
||||
@Service("CONFIRM_ZESA")
|
||||
@RequiredArgsConstructor
|
||||
public class ZesaConfirmationProcessor implements TransactionProcessorInterface {
|
||||
private final RestService restService;
|
||||
|
||||
@Value("${sbz.aggregator.url}")
|
||||
private String aggregatorUrl;
|
||||
|
||||
@Override
|
||||
public Object process(Transaction transaction) {
|
||||
|
||||
return transaction;
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
System.out.println("processing transaction");
|
||||
throw new Exception("Challenge encountered, please contact support.");
|
||||
// return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
|
||||
public class CalculateChargesHandler implements LogicHandler<Transaction, Transaction> {
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
System.out.println("processing charges");
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
interface LogicHandler<I, O> {
|
||||
O process(I input);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
public class LogicPipeline<I, O> {
|
||||
|
||||
private final LogicHandler<I, O> currentHandler;
|
||||
|
||||
public LogicPipeline(LogicHandler<I, O> currentHandler) {
|
||||
this.currentHandler = currentHandler;
|
||||
}
|
||||
|
||||
public <K> LogicPipeline<I, K> addHandler(LogicHandler<O, K> newHandler) {
|
||||
return new LogicPipeline<>(input -> newHandler.process(currentHandler.process(input)));
|
||||
}
|
||||
|
||||
public O execute(I input) {
|
||||
return currentHandler.process(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
|
||||
public class ValidationHandler implements LogicHandler<Transaction, Transaction> {
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
System.out.println("processing validation");
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package zw.qantra.tm.domain.services.processors.integrations;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
|
||||
@Service("REQUEST_ZESA")
|
||||
@RequiredArgsConstructor
|
||||
public class ZesaIntegrationProcessor implements TransactionProcessorInterface {
|
||||
private final RestService restService;
|
||||
|
||||
@Value("${sbz.aggregator.url}")
|
||||
private String aggregatorUrl;
|
||||
|
||||
@Override
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object reverse(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package zw.qantra.tm.domain.services.processors.payments;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
|
||||
@Service("STEWARD_WEB")
|
||||
@RequiredArgsConstructor
|
||||
public class StewardWebPaymentProcessor implements TransactionProcessorInterface {
|
||||
private final RestService restService;
|
||||
|
||||
|
||||
@Override
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object reverse(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -12,3 +12,5 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/qpay?useLegacyDatetimeCode=false
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=password
|
||||
|
||||
sbz.aggregator.url=http://192.168.16.29:24050/v1
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
spring.application.name=tm
|
||||
debug=true
|
||||
|
||||
server.servlet.context-path=/api
|
||||
|
||||
logging.level.root=INFO
|
||||
logging.level.org.springframework.boot.autoconfigure=INFO
|
||||
|
||||
@@ -12,3 +15,5 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/qpay?useLegacyDatetimeCode=false
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=password
|
||||
|
||||
sbz.aggregator.url=http://192.168.16.29:24050/v1
|
||||
Reference in New Issue
Block a user