poc completed
This commit is contained in:
@@ -30,6 +30,13 @@ public class ProviderService {
|
||||
@Value("${sbz.aggregator.url}")
|
||||
private String aggregatorUrl;
|
||||
|
||||
public SBZProductDto getProviderProduct(UUID providerId, UUID productId) {
|
||||
return getProviderProducts(providerId).stream()
|
||||
.filter(product -> product.getUid().equals(productId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public List<SBZProductDto> getProviderProducts(UUID providerId) {
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
@@ -57,13 +64,15 @@ public class ProviderService {
|
||||
return products;
|
||||
}
|
||||
|
||||
public Object getProviders(String category) {
|
||||
String token = restService.getMerchantToken();
|
||||
public Object getProviderByClientId(String clientId) {
|
||||
Provider provider = providerRepository.findByClientId(clientId);
|
||||
if (provider != null) {
|
||||
return ((List)getProviders(Collections.singletonList(provider))).stream().findFirst().orElse(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
headers.setBearerAuth(token);
|
||||
public Object getProvidersByCategory(String category) {
|
||||
|
||||
List<Provider> existingProviders;
|
||||
if (category != null && !category.isEmpty()) {
|
||||
@@ -72,6 +81,17 @@ public class ProviderService {
|
||||
existingProviders = getProviderRepository().findAll();
|
||||
}
|
||||
|
||||
return getProviders(existingProviders);
|
||||
}
|
||||
|
||||
public Object getProviders(List<Provider> existingProviders) {
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
headers.setBearerAuth(token);
|
||||
|
||||
List<String> existingProviderIds = existingProviders.stream()
|
||||
.map(Provider::getClientId)
|
||||
.collect(Collectors.toList());
|
||||
@@ -100,6 +120,7 @@ public class ProviderService {
|
||||
provider.put("image", existingProvider.getImage());
|
||||
provider.put("label", existingProvider.getLabel());
|
||||
provider.put("category", existingProvider.getCategory());
|
||||
provider.put("accountFieldName", existingProvider.getAccountFieldName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package zw.qantra.tm.domain.services;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.models.Recipient;
|
||||
import zw.qantra.tm.domain.repositories.RecipientRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RecipientService {
|
||||
@Getter
|
||||
private final RecipientRepository recipientRepository;
|
||||
|
||||
public List<Recipient> getAllRecipients() {
|
||||
return recipientRepository.findAll();
|
||||
}
|
||||
|
||||
public List<Recipient> getRecipient(String account, String userId) {
|
||||
return recipientRepository.findByAccountAndUserId(account, userId);
|
||||
}
|
||||
|
||||
public Recipient save(Recipient recipient) {
|
||||
return recipientRepository.save(recipient);
|
||||
}
|
||||
|
||||
public Recipient updateRecipient(UUID id, Recipient recipient) {
|
||||
if (recipientRepository.existsById(id)) {
|
||||
recipient.setId(id);
|
||||
return recipientRepository.save(recipient);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean deleteRecipient(UUID id) {
|
||||
if (recipientRepository.existsById(id)) {
|
||||
recipientRepository.deleteById(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Recipient> searchRecipients(Specification<Recipient> specification) {
|
||||
return recipientRepository.findAll(specification);
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,34 @@ package zw.qantra.tm.domain.services;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import zw.qantra.tm.domain.enums.RequestType;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.AdditionalData;
|
||||
import zw.qantra.tm.domain.models.Provider;
|
||||
import zw.qantra.tm.domain.models.Recipient;
|
||||
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.ConfirmationLogicHandler;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.FormattingHandler;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.LogicPipeline;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.RecipientsUpdateHandler;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.ValidationHandler;
|
||||
import zw.qantra.tm.exceptions.ApiException;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -29,42 +40,25 @@ public class TransactionService {
|
||||
@Getter
|
||||
private final TransactionRepository transactionRepository;
|
||||
private final PaymentProcessorFactory paymentProcessorFactory;
|
||||
private final CalculateChargesHandler calculateChargesHandler;
|
||||
private final ProviderService providerService;
|
||||
private final ChargeService chargeService;
|
||||
private final AdditionalDataService additionalDataService;
|
||||
private final RecipientService recipientService;
|
||||
|
||||
public Transaction poll(UUID uuid){
|
||||
if(!transactionRepository.existsById(uuid)){
|
||||
throw new ApiException("Transaction not found for ID: " + uuid);
|
||||
}
|
||||
|
||||
Transaction transaction = transactionRepository.findById(uuid).get();
|
||||
|
||||
// no persistence happens during polling unless the transaction status changes
|
||||
String label = getLabel(transaction);
|
||||
logger.info("label: {}", label);
|
||||
|
||||
TransactionProcessorInterface transactionProcessorInterface =
|
||||
(TransactionProcessorInterface) paymentProcessorFactory.getPaymentProcessor(label);
|
||||
try {
|
||||
transactionProcessorInterface.poll(transaction);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("01");
|
||||
transaction.setErrorMessage(e.getMessage());
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public Transaction execute(Transaction transaction) {
|
||||
transaction.setReference(UUID.randomUUID().toString());
|
||||
public Transaction integration(Transaction transaction) {
|
||||
transaction.setType(RequestType.INTEGRATION);
|
||||
|
||||
LogicPipeline<Transaction, Transaction> transactionLogic =
|
||||
new LogicPipeline<>(calculateChargesHandler)
|
||||
.addHandler(new ValidationHandler());
|
||||
new LogicPipeline<>(new ValidationHandler());
|
||||
transaction = transactionLogic.execute(transaction);
|
||||
|
||||
String label = getLabel(transaction);
|
||||
Provider provider = providerService.getProviderRepository()
|
||||
.findByClientId(transaction.getBillClientId());
|
||||
if(provider == null){
|
||||
throw new ApiException("Provider not found for billClientId: " + transaction.getBillClientId());
|
||||
}
|
||||
String label = transaction.getType() + "_" +
|
||||
provider.getIntegrationProcessorLabel();
|
||||
logger.info("label: {}", label);
|
||||
|
||||
TransactionProcessorInterface transactionProcessorInterface =
|
||||
@@ -83,9 +77,80 @@ public class TransactionService {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public Transaction poll(UUID uuid){
|
||||
if(!transactionRepository.existsById(uuid)){
|
||||
throw new ApiException("Transaction not found for ID: " + uuid);
|
||||
}
|
||||
|
||||
Transaction transaction = transactionRepository.findById(uuid).get();
|
||||
|
||||
// no persistence happens during polling unless the transaction status changes
|
||||
String label = getLabel(transaction);
|
||||
logger.info("label: {}", label);
|
||||
|
||||
TransactionProcessorInterface transactionProcessorInterface =
|
||||
(TransactionProcessorInterface) paymentProcessorFactory.getPaymentProcessor(label);
|
||||
try {
|
||||
// find out if the gateway tran was successful
|
||||
transactionProcessorInterface.poll(transaction);
|
||||
|
||||
// if tran was successful deep copy transaction & push integration to the aggregator
|
||||
Transaction transactionCopy = Utils.deepCopy(transaction, Transaction.class);
|
||||
transactionCopy.setType(RequestType.INTEGRATION);
|
||||
transactionCopy.setId(null);
|
||||
integration(transactionCopy);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("01");
|
||||
transaction.setErrorMessage(e.getMessage());
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public Transaction execute(Transaction transaction) {
|
||||
transaction.setReference(UUID.randomUUID().toString());
|
||||
|
||||
// run pre transaction logic
|
||||
LogicPipeline<Transaction, Transaction> preTransactionLogic =
|
||||
new LogicPipeline<>(new CalculateChargesHandler(chargeService))
|
||||
.addHandler(new ConfirmationLogicHandler())
|
||||
.addHandler(new FormattingHandler())
|
||||
.addHandler(new ValidationHandler());
|
||||
transaction = preTransactionLogic.execute(transaction);
|
||||
|
||||
String label = getLabel(transaction);
|
||||
logger.info("label: {}", label);
|
||||
|
||||
TransactionProcessorInterface transactionProcessorInterface =
|
||||
(TransactionProcessorInterface) paymentProcessorFactory.getPaymentProcessor(label);
|
||||
|
||||
try {
|
||||
// MAIN TRANSACTION LOGIC!
|
||||
transactionProcessorInterface.process(transaction);
|
||||
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("01");
|
||||
transaction.setErrorMessage(e.getMessage());
|
||||
transactionRepository.save(transaction);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// run post transaction logic
|
||||
LogicPipeline<Transaction, Transaction> postTransactionLogic =
|
||||
new LogicPipeline<>(new RecipientsUpdateHandler(recipientService));
|
||||
transaction = postTransactionLogic.execute(transaction);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private String getLabel(Transaction transaction){
|
||||
String label = "";
|
||||
if(transaction.getType() == RequestType.CONFIRM){
|
||||
List<RequestType> list = Arrays.asList(RequestType.CONFIRM);
|
||||
if(list.contains(transaction.getType())){
|
||||
// get processor label from billClientId
|
||||
Provider provider = providerService.getProviderRepository()
|
||||
.findByClientId(transaction.getBillClientId());
|
||||
@@ -102,6 +167,20 @@ public class TransactionService {
|
||||
return label;
|
||||
}
|
||||
|
||||
public Transaction findById(UUID id) {
|
||||
Transaction transaction = transactionRepository.findById(id).orElseThrow(() -> new ApiException("Transaction not found for ID: " + id));
|
||||
|
||||
AdditionalData additionalData = additionalDataService.getAdditionalDataRepository()
|
||||
.findByTransactionId(id).orElseThrow(() -> new ApiException("Additional data not found for transaction ID: " + id));
|
||||
transaction.setAdditionalData(Utils.fromJson(additionalData.getJsonString(), List.class));
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public List<Transaction> findAll(Specification<Transaction> spec) {
|
||||
return transactionRepository.findAll(spec, Sort.by(Sort.Direction.ASC, "createdAt"));
|
||||
}
|
||||
|
||||
public Transaction save(Transaction transaction){
|
||||
return transactionRepository.save(transaction);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package zw.qantra.tm.domain.services.processors.confirmations;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.dtos.BillPaymentDto;
|
||||
import zw.qantra.tm.domain.enums.RequestType;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.AdditionalData;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.AdditionalDataService;
|
||||
import zw.qantra.tm.domain.services.TransactionService;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
@Service("CONFIRM_ECONET")
|
||||
@RequiredArgsConstructor
|
||||
public class EconetConfirmationProcessor implements TransactionProcessorInterface {
|
||||
Logger logger = LoggerFactory.getLogger(EconetConfirmationProcessor.class);
|
||||
|
||||
private final RestService restService;
|
||||
private final TransactionService transactionService;
|
||||
private final AdditionalDataService additionalDataService;
|
||||
|
||||
@Value("${sbz.aggregator.url}")
|
||||
private String aggregatorUrl;
|
||||
@Value("${sbz.aggregator.client-id}")
|
||||
private String aggregatorClientId;
|
||||
@Value("${sbz.aggregator.phone}")
|
||||
private String aggregatorPhone;
|
||||
@Value("${sbz.aggregator.account}")
|
||||
private String aggregatorAccount;
|
||||
|
||||
@Override
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
logger.info("processing transaction");
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
BillPaymentDto request = BillPaymentDto.builder()
|
||||
.type(RequestType.CONFIRM)
|
||||
.billClientId(transaction.getBillClientId())
|
||||
.debitRef(transaction.getDebitRef())
|
||||
.debitCurrency(transaction.getDebitCurrency())
|
||||
.amount(transaction.getAmount())
|
||||
.aggregatorId(aggregatorClientId)
|
||||
.debitPhone(aggregatorPhone) // qantra mobile number
|
||||
.debitAccount(aggregatorAccount) // qantra corporate account
|
||||
.creditAccount(transaction.getCreditAccount()) // customer's phone number
|
||||
.creditPhone(transaction.getCreditPhone()) // customer's contact phone number
|
||||
.billName(transaction.getBillName())
|
||||
.build();
|
||||
|
||||
String url = aggregatorUrl + "/merchant/aggregation/transaction";
|
||||
|
||||
LinkedHashMap response = restService.postWithToken(token, url, request, LinkedHashMap.class);
|
||||
|
||||
logger.info("response: {}", response.toString());
|
||||
|
||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||
|
||||
if (body.get("status").equals("SUCCESS")) {
|
||||
transaction.setStatus(Status.SUCCESS);
|
||||
transaction.setResponseCode((String) body.get("responseCode"));
|
||||
transaction.setAdditionalData(body.get("additionalData"));
|
||||
transactionService.save(transaction);
|
||||
|
||||
AdditionalData additionalData = AdditionalData.builder()
|
||||
.transaction(transaction)
|
||||
.jsonString(Utils.toJson(body.get("additionalData")))
|
||||
.build();
|
||||
additionalDataService.getAdditionalDataRepository().save(additionalData);
|
||||
|
||||
} else {
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setErrorMessage((String) body.get("message"));
|
||||
transaction.setResponseCode((String) body.get("responseCode"));
|
||||
transaction.setErrorMessage((String) body.get("errorMessage"));
|
||||
}
|
||||
|
||||
return transactionService.save(transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object reverse(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poll(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,7 @@ public class ZesaConfirmationProcessor implements TransactionProcessorInterface
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setErrorMessage((String) body.get("message"));
|
||||
transaction.setResponseCode((String) body.get("responseCode"));
|
||||
transaction.setErrorMessage((String) body.get("errorMessage"));
|
||||
}
|
||||
|
||||
return transactionService.save(transaction);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -17,11 +18,11 @@ import java.util.List;
|
||||
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CalculateChargesHandler implements LogicHandler<Transaction, Transaction> {
|
||||
Logger logger = LoggerFactory.getLogger(CalculateChargesHandler.class);
|
||||
|
||||
@Autowired
|
||||
private ChargeService chargeService;
|
||||
private final ChargeService chargeService;
|
||||
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
@@ -126,14 +127,17 @@ public class CalculateChargesHandler implements LogicHandler<Transaction, Transa
|
||||
|
||||
// calculate total amount for ease of use later
|
||||
transaction.setTotalAmount(
|
||||
transaction.getAmount().add(
|
||||
transaction.getCharge().add(
|
||||
transaction.getTax().add(
|
||||
transaction.getGatewayCharge())));
|
||||
transaction.getGatewayCharge()))));
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
void applyCharge(Transaction transaction, Charge charge, BigDecimal chargeAmount) {
|
||||
if(chargeAmount == null) return;
|
||||
|
||||
switch (charge.getChargeLabel()) {
|
||||
case FEE -> transaction.setCharge(chargeAmount);
|
||||
case TAX -> transaction.setTax(chargeAmount);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import zw.qantra.tm.domain.enums.RequestType;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
public class ConfirmationLogicHandler implements LogicHandler<Transaction, Transaction> {
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
if(transaction.getType().equals(RequestType.CONFIRM)) {
|
||||
transaction.setTrace(Utils.getUid());
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import com.google.i18n.phonenumbers.NumberParseException;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
||||
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
|
||||
public class FormattingHandler implements LogicHandler<Transaction, Transaction> {
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
System.out.println("processing formatting");
|
||||
|
||||
// strip credit account and make sure there's nothing funny
|
||||
String creditAccount = transaction.getCreditAccount();
|
||||
if (creditAccount != null && !creditAccount.isEmpty()) {
|
||||
// Remove all non-hexadecimal characters (keep only 0-9, a-f, A-F)
|
||||
String strippedAccount = creditAccount.replaceAll("[^0-9a-fA-F]", "");
|
||||
|
||||
// Only set if the stripped result is not empty
|
||||
if (!strippedAccount.isEmpty()) {
|
||||
transaction.setCreditAccount(strippedAccount);
|
||||
} else {
|
||||
// If stripping results in empty string, set to null
|
||||
transaction.setCreditAccount(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sanitize phone number formatting
|
||||
String debitPhoneNumber = transaction.getDebitPhone();
|
||||
String creditPhoneNumber = transaction.getCreditPhone();
|
||||
|
||||
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
|
||||
|
||||
if(debitPhoneNumber != null && !debitPhoneNumber.isEmpty()){
|
||||
try {
|
||||
// phone must begin with '+'
|
||||
PhoneNumber zimPhoneNumber = phoneUtil.parse(debitPhoneNumber, "");
|
||||
String formattedPhoneNumber = phoneUtil.format(zimPhoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
transaction.setDebitPhone(formattedPhoneNumber);
|
||||
} catch (NumberParseException e) {
|
||||
System.err.println("NumberParseException was thrown: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if(creditPhoneNumber != null && !creditPhoneNumber.isEmpty()){
|
||||
try {
|
||||
PhoneNumber zimPhoneNumber = phoneUtil.parse(creditPhoneNumber, "");
|
||||
String formattedPhoneNumber = phoneUtil.format(zimPhoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
transaction.setCreditPhone(formattedPhoneNumber);
|
||||
} catch (NumberParseException e) {
|
||||
System.err.println("NumberParseException was thrown: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.Recipient;
|
||||
import zw.qantra.tm.domain.services.RecipientService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RecipientsUpdateHandler implements LogicHandler<Transaction, Transaction> {
|
||||
|
||||
private final RecipientService recipientService;
|
||||
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
System.out.println("processing recipients");
|
||||
|
||||
if(transaction.getStatus() == Status.SUCCESS){
|
||||
List<Recipient> recipients = recipientService.getRecipient(transaction.getCreditAccount(), transaction.getUserId());
|
||||
|
||||
Recipient recipient = null;
|
||||
if(recipients.size() > 0){
|
||||
recipient = recipients.get(0);
|
||||
}else{
|
||||
recipient = new Recipient();
|
||||
recipient.setAccount(transaction.getCreditAccount());
|
||||
recipient.setUserId(transaction.getUserId());
|
||||
}
|
||||
|
||||
recipient.setLatestProviderLabel(transaction.getProviderLabel());
|
||||
if(transaction.getCreditName() != null && !transaction.getCreditName().isEmpty()){
|
||||
recipient.setName(transaction.getCreditName());
|
||||
}
|
||||
if(transaction.getCreditEmail() != null && !transaction.getCreditEmail().isEmpty()){
|
||||
recipient.setEmail(transaction.getCreditEmail());
|
||||
}
|
||||
if(transaction.getCreditPhone() != null && !transaction.getCreditPhone().isEmpty()){
|
||||
recipient.setPhoneNumber(transaction.getCreditPhone());
|
||||
}
|
||||
|
||||
String stringToInitial = transaction.getCreditName() != null && !transaction.getCreditName().isEmpty()
|
||||
? transaction.getCreditName() : transaction.getBillName();
|
||||
|
||||
recipient.setInitials(stringToInitial.substring(0, 2).toUpperCase());
|
||||
recipientService.save(recipient);
|
||||
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package zw.qantra.tm.domain.services.processors.integrations;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.dtos.BillPaymentDto;
|
||||
import zw.qantra.tm.domain.enums.RequestType;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.AdditionalData;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.AdditionalDataService;
|
||||
import zw.qantra.tm.domain.services.TransactionService;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
@Service("INTEGRATION_STEWARD")
|
||||
@RequiredArgsConstructor
|
||||
public class StewardIntegrationProcessor implements TransactionProcessorInterface {
|
||||
Logger logger = LoggerFactory.getLogger(TransactionService.class);
|
||||
private final RestService restService;
|
||||
private final TransactionService transactionService;
|
||||
private final AdditionalDataService additionalDataService;
|
||||
|
||||
@Value("${sbz.aggregator.url}")
|
||||
private String aggregatorUrl;
|
||||
@Value("${sbz.aggregator.client-id}")
|
||||
private String aggregatorClientId;
|
||||
@Value("${sbz.aggregator.phone}")
|
||||
private String aggregatorPhone;
|
||||
@Value("${sbz.aggregator.account}")
|
||||
private String aggregatorAccount;
|
||||
|
||||
@Override
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
logger.info("processing integration");
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
BillPaymentDto request = BillPaymentDto.builder()
|
||||
.type(RequestType.REQUEST)
|
||||
.billClientId(transaction.getBillClientId())
|
||||
.debitRef(transaction.getDebitRef())
|
||||
.debitCurrency(transaction.getDebitCurrency())
|
||||
.amount(transaction.getAmount())
|
||||
.aggregatorId(aggregatorClientId)
|
||||
.debitPhone(aggregatorPhone) // qantra mobile number
|
||||
.debitAccount(aggregatorAccount) // qantra corporate account
|
||||
.creditAccount(transaction.getCreditAccount()) // customer's zesa meter number
|
||||
.creditPhone(transaction.getCreditPhone()) // customer's contact phone number
|
||||
.billName(transaction.getBillName())
|
||||
.authType(transaction.getAuthType())
|
||||
.trace(transaction.getTrace())
|
||||
.build();
|
||||
|
||||
String url = aggregatorUrl + "/merchant/aggregation/transaction";
|
||||
|
||||
LinkedHashMap response = restService.postWithToken(token, url, request, LinkedHashMap.class);
|
||||
|
||||
logger.info("response: {}", response.toString());
|
||||
|
||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||
|
||||
if (body.get("status").equals("SUCCESS")) {
|
||||
transaction.setStatus(Status.SUCCESS);
|
||||
transaction.setResponseCode((String) body.get("responseCode"));
|
||||
transaction.setAdditionalData(body.get("additionalData"));
|
||||
transactionService.save(transaction);
|
||||
|
||||
AdditionalData additionalData = AdditionalData.builder()
|
||||
.transaction(transaction)
|
||||
.jsonString(Utils.toJson(body.get("additionalData")))
|
||||
.build();
|
||||
additionalDataService.getAdditionalDataRepository().save(additionalData);
|
||||
|
||||
// fetch the corresponding request transaction if it exists
|
||||
Transaction requestTransaction = transactionService.getTransactionRepository()
|
||||
.findByTraceAndType(transaction.getTrace(), RequestType.REQUEST);
|
||||
if (requestTransaction != null) {
|
||||
// create a new additional data for the request transaction
|
||||
AdditionalData requestAdditionalData = AdditionalData.builder()
|
||||
.transaction(requestTransaction)
|
||||
.jsonString(Utils.toJson(body.get("additionalData")))
|
||||
.build();
|
||||
additionalDataService.getAdditionalDataRepository().save(requestAdditionalData);
|
||||
}
|
||||
|
||||
} else {
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setErrorMessage((String) body.get("message"));
|
||||
transaction.setResponseCode((String) body.get("responseCode"));
|
||||
transaction.setErrorMessage((String) body.get("errorMessage"));
|
||||
}
|
||||
|
||||
return transactionService.save(transaction);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object reverse(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poll(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poll(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -40,10 +42,13 @@ public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
||||
logger.info("processing transaction");
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
// send total less gateway charges
|
||||
BigDecimal totalAmount = transaction.getAmount().add(transaction.getTax()).add(transaction.getCharge());
|
||||
|
||||
String concat = clientId+
|
||||
encryptionKey+
|
||||
transaction.getCreditPhone()+
|
||||
transaction.getAmount();
|
||||
totalAmount;
|
||||
|
||||
String hex = getHash(concat);
|
||||
|
||||
@@ -51,7 +56,7 @@ public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.phone(transaction.getCreditPhone())
|
||||
.amount(transaction.getAmount().toString())
|
||||
.amount(totalAmount.toString())
|
||||
.currency(transaction.getDebitCurrency().toString())
|
||||
.hash(hex)
|
||||
.authType("WEB")
|
||||
@@ -59,7 +64,7 @@ public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
||||
.action("PAYMENT")
|
||||
.sandbox(true)
|
||||
.paymentProcessorLabel("MPGS")
|
||||
.responseUrl("https://www.google.com")
|
||||
.responseUrl("https://stewardbank.co.zw")
|
||||
.build();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
Reference in New Issue
Block a user