completed zesa journey
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
package zw.qantra.tm.domain.services;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.models.AdditionalData;
|
||||
import zw.qantra.tm.domain.repositories.AdditionalDataRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AdditionalDataService {
|
||||
private final AdditionalDataRepository additionalDataRepository;
|
||||
|
||||
public List<AdditionalData> getAllAdditionalData() {
|
||||
return additionalDataRepository.findAll();
|
||||
}
|
||||
|
||||
public Optional<AdditionalData> getAdditionalData(UUID id) {
|
||||
return additionalDataRepository.findById(id);
|
||||
}
|
||||
|
||||
public AdditionalData createAdditionalData(AdditionalData additionalData) {
|
||||
return additionalDataRepository.save(additionalData);
|
||||
}
|
||||
|
||||
public AdditionalData updateAdditionalData(UUID id, AdditionalData additionalData) {
|
||||
if (additionalDataRepository.existsById(id)) {
|
||||
additionalData.setId(id);
|
||||
return additionalDataRepository.save(additionalData);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean deleteAdditionalData(UUID id) {
|
||||
if (additionalDataRepository.existsById(id)) {
|
||||
additionalDataRepository.deleteById(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package zw.qantra.tm.domain.services;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.text.WordUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -64,7 +66,7 @@ public class ProviderService {
|
||||
headers.setBearerAuth(token);
|
||||
|
||||
List<Provider> existingProviders;
|
||||
if (category != null) {
|
||||
if (category != null && !category.isEmpty()) {
|
||||
existingProviders = getProviderRepository().findByCategory(category);
|
||||
} else {
|
||||
existingProviders = getProviderRepository().findAll();
|
||||
@@ -84,6 +86,24 @@ public class ProviderService {
|
||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||
List<LinkedHashMap> content = (List<LinkedHashMap>) body.get("content");
|
||||
|
||||
for (LinkedHashMap provider : content) {
|
||||
String clientId = (String) provider.get("clientId");
|
||||
if (existingProviderIds.contains(clientId)) {
|
||||
// Update existing provider
|
||||
Provider existingProvider = existingProviders.stream()
|
||||
.filter(p -> p.getClientId().equals(clientId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (existingProvider != null) {
|
||||
provider.put("name", WordUtils.capitalizeFully((String)provider.get("name")));
|
||||
provider.put("description", existingProvider.getDescription());
|
||||
provider.put("image", existingProvider.getImage());
|
||||
provider.put("label", existingProvider.getLabel());
|
||||
provider.put("category", existingProvider.getCategory());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
package zw.qantra.tm.domain.services;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.Provider;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.repositories.TransactionRepository;
|
||||
import zw.qantra.tm.domain.services.factories.PaymentProcessorFactory;
|
||||
@@ -10,27 +19,54 @@ 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;
|
||||
import zw.qantra.tm.exceptions.ApiException;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TransactionService {
|
||||
Logger logger = LoggerFactory.getLogger(TransactionService.class);
|
||||
|
||||
@Getter
|
||||
private final TransactionRepository transactionRepository;
|
||||
private final PaymentProcessorFactory paymentProcessorFactory;
|
||||
private final CalculateChargesHandler calculateChargesHandler;
|
||||
private final ProviderService providerService;
|
||||
|
||||
public TransactionRepository getTransactionRepository() {
|
||||
return transactionRepository;
|
||||
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());
|
||||
|
||||
LogicPipeline<Transaction, Transaction> transactionLogic =
|
||||
new LogicPipeline<>(calculateChargesHandler)
|
||||
.addHandler(new ValidationHandler());
|
||||
|
||||
transaction = transactionLogic.execute(transaction);
|
||||
|
||||
String label = transaction.getType() + "_" + transaction.getIntegrationProcessorLabel();
|
||||
String label = getLabel(transaction);
|
||||
logger.info("label: {}", label);
|
||||
|
||||
TransactionProcessorInterface transactionProcessorInterface =
|
||||
(TransactionProcessorInterface) paymentProcessorFactory.getPaymentProcessor(label);
|
||||
|
||||
@@ -46,4 +82,27 @@ public class TransactionService {
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private String getLabel(Transaction transaction){
|
||||
String label = "";
|
||||
if(transaction.getType() == RequestType.CONFIRM){
|
||||
// get processor label from billClientId
|
||||
Provider provider = providerService.getProviderRepository()
|
||||
.findByClientId(transaction.getBillClientId());
|
||||
if(provider == null){
|
||||
throw new ApiException("Provider not found for billClientId: " + transaction.getBillClientId());
|
||||
}
|
||||
label = transaction.getType() + "_" +
|
||||
provider.getLabel();
|
||||
}else{
|
||||
label = transaction.getType() + "_" +
|
||||
transaction.getPaymentProcessorLabel() + "_" +
|
||||
transaction.getAuthType();
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
public Transaction save(Transaction transaction){
|
||||
return transactionRepository.save(transaction);
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,5 @@ import zw.qantra.tm.domain.models.Transaction;
|
||||
public interface TransactionProcessorInterface {
|
||||
Object process(Transaction transaction) throws Exception;
|
||||
Object reverse(Transaction transaction);
|
||||
Object poll(Transaction transaction) throws Exception;
|
||||
}
|
||||
|
||||
@@ -1,27 +1,45 @@
|
||||
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.Map;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
@Service("CONFIRM_ZESA")
|
||||
@RequiredArgsConstructor
|
||||
public class ZesaConfirmationProcessor implements TransactionProcessorInterface {
|
||||
Logger logger = LoggerFactory.getLogger(ZesaConfirmationProcessor.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 {
|
||||
System.out.println("processing transaction");
|
||||
logger.info("processing transaction");
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
BillPaymentDto request = BillPaymentDto.builder()
|
||||
@@ -30,25 +48,50 @@ public class ZesaConfirmationProcessor implements TransactionProcessorInterface
|
||||
.debitRef(transaction.getDebitRef())
|
||||
.debitCurrency(transaction.getDebitCurrency())
|
||||
.amount(transaction.getAmount())
|
||||
.aggregatorId(transaction.getAggregatorId())
|
||||
.debitPhone(transaction.getDebitPhone())
|
||||
.debitAccount(transaction.getDebitAccount())
|
||||
.creditAccount(transaction.getCreditAccount())
|
||||
.creditPhone(transaction.getCreditPhone())
|
||||
.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())
|
||||
.build();
|
||||
|
||||
String url = aggregatorUrl + "/v1/merchant/aggregation/transaction";
|
||||
String url = aggregatorUrl + "/merchant/aggregation/transaction";
|
||||
|
||||
Map response = restService.postWithToken(token, url, request, Map.class);
|
||||
LinkedHashMap response = restService.postWithToken(token, url, request, LinkedHashMap.class);
|
||||
|
||||
System.out.println(response);
|
||||
logger.info("response: {}", response.toString());
|
||||
|
||||
return transaction;
|
||||
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"));
|
||||
}
|
||||
|
||||
return transactionService.save(transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object reverse(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poll(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.models.Charge;
|
||||
import zw.qantra.tm.domain.models.ChargeCondition;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.ChargeConditionService;
|
||||
import zw.qantra.tm.domain.services.ChargeService;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -15,15 +16,16 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@AllArgsConstructor
|
||||
@Service
|
||||
public class CalculateChargesHandler implements LogicHandler<Transaction, Transaction> {
|
||||
private ChargeConditionService chargeConditionService;
|
||||
Logger logger = LoggerFactory.getLogger(CalculateChargesHandler.class);
|
||||
|
||||
@Autowired
|
||||
private ChargeService chargeService;
|
||||
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
System.out.println("processing charges");
|
||||
logger.info("processing charges");
|
||||
transaction.setCharge(BigDecimal.ZERO);
|
||||
transaction.setTax(BigDecimal.ZERO);
|
||||
transaction.setGatewayCharge(BigDecimal.ZERO);
|
||||
@@ -122,6 +124,12 @@ public class CalculateChargesHandler implements LogicHandler<Transaction, Transa
|
||||
applyCharge(transaction, charge, chargeAmount);
|
||||
}
|
||||
|
||||
// calculate total amount for ease of use later
|
||||
transaction.setTotalAmount(
|
||||
transaction.getCharge().add(
|
||||
transaction.getTax().add(
|
||||
transaction.getGatewayCharge())));
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,4 +25,10 @@ public class ZesaIntegrationProcessor implements TransactionProcessorInterface {
|
||||
public Object reverse(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poll(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package zw.qantra.tm.domain.services.processors.payments;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.dtos.SdkActionDto;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
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.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
@Service("REQUEST_MPGS_WEB")
|
||||
@RequiredArgsConstructor
|
||||
public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
||||
private final Logger logger = LoggerFactory.getLogger(MPGSWebPaymentProcessor.class);
|
||||
private final RestService restService;
|
||||
private final TransactionService transactionService;
|
||||
|
||||
@Value("${sbz.aggregator.encryption-key}")
|
||||
private String encryptionKey;
|
||||
@Value("${sbz.aggregator.client-id}")
|
||||
private String clientId;
|
||||
@Value("${sbz.aggregator.client-secret}")
|
||||
private String clientSecret;
|
||||
@Value("${steward.payment.processor.url}")
|
||||
private String url;
|
||||
|
||||
@Override
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
logger.info("processing transaction");
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
String concat = clientId+
|
||||
encryptionKey+
|
||||
transaction.getCreditPhone()+
|
||||
transaction.getAmount();
|
||||
|
||||
String hex = getHash(concat);
|
||||
|
||||
SdkActionDto sdkActionDto = SdkActionDto.builder()
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.phone(transaction.getCreditPhone())
|
||||
.amount(transaction.getAmount().toString())
|
||||
.currency(transaction.getDebitCurrency().toString())
|
||||
.hash(hex)
|
||||
.authType("WEB")
|
||||
.billerReference(transaction.getReference())
|
||||
.action("PAYMENT")
|
||||
.sandbox(true)
|
||||
.paymentProcessorLabel("MPGS")
|
||||
.responseUrl("https://www.google.com")
|
||||
.build();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Authorization", "Bearer " + token);
|
||||
headers.set("Content-Type", "application/json");
|
||||
|
||||
try {
|
||||
LinkedHashMap response = restService.postAs(url + "/merchant/sdk/action",
|
||||
sdkActionDto, headers, LinkedHashMap.class);
|
||||
logger.info("response: {}", Utils.toJson(response));
|
||||
|
||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||
transaction.setSdkActionId((String) body.get("uid"));
|
||||
|
||||
if(!body.get("status").equals("FAILED")){
|
||||
transaction.setStatus(Status.PENDING);
|
||||
transaction.setResponseCode("00");
|
||||
transaction.setTargetUrl((String) body.get("targetUrl"));
|
||||
}else{
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("01");
|
||||
transaction.setErrorMessage((String) body.get("message"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("99");
|
||||
transaction.setErrorMessage("Network error: " + e.getMessage());
|
||||
}
|
||||
|
||||
return transactionService.save(transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poll(Transaction transaction) throws Exception {
|
||||
logger.info("polling transaction");
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Authorization", "Bearer " + token);
|
||||
headers.set("Content-Type", "application/json");
|
||||
|
||||
try {
|
||||
LinkedHashMap response = restService.getAs(url + "/merchant/sdk/mpgs/poll/" + transaction.getSdkActionId(),
|
||||
headers, LinkedHashMap.class);
|
||||
logger.info("response: {}", Utils.toJson(response));
|
||||
|
||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||
|
||||
// only update tran status if polling returns a success
|
||||
if(body.get("status").equals("SUCCESS")){
|
||||
transaction.setStatus(Status.SUCCESS);
|
||||
transaction.setResponseCode("00");
|
||||
transaction.setTargetUrl((String) body.get("targetUrl"));
|
||||
transactionService.save(transaction);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("99");
|
||||
transaction.setErrorMessage("Network error: " + e.getMessage());
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object reverse(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public String getHash(String originalString){
|
||||
String hex = "";
|
||||
MessageDigest digest = null;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] encodedhash = digest.digest(
|
||||
originalString.getBytes(StandardCharsets.UTF_8));
|
||||
hex = bytesToHex(encodedhash);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] hash) {
|
||||
StringBuilder hexString = new StringBuilder(2 * hash.length);
|
||||
for (int i = 0; i < hash.length; i++) {
|
||||
String hex = Integer.toHexString(0xff & hash[i]);
|
||||
if(hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,131 @@
|
||||
package zw.qantra.tm.domain.services.processors.payments;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import zw.qantra.tm.domain.dtos.SdkActionDto;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.domain.services.TransactionService;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
@Service("STEWARD_WEB")
|
||||
@Service("REQUEST_STEWARD_WEB")
|
||||
@RequiredArgsConstructor
|
||||
public class StewardWebPaymentProcessor implements TransactionProcessorInterface {
|
||||
private final Logger logger = LoggerFactory.getLogger(StewardWebPaymentProcessor.class);
|
||||
private final RestService restService;
|
||||
private final TransactionService transactionService;
|
||||
|
||||
@Value("${sbz.aggregator.encryption-key}")
|
||||
private String encryptionKey;
|
||||
@Value("${sbz.aggregator.client-id}")
|
||||
private String clientId;
|
||||
@Value("${sbz.aggregator.client-secret}")
|
||||
private String clientSecret;
|
||||
@Value("${steward.payment.processor.url}")
|
||||
private String url;
|
||||
|
||||
@Override
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
return transaction;
|
||||
logger.info("processing transaction");
|
||||
String token = restService.getMerchantToken();
|
||||
|
||||
String concat = clientId+
|
||||
encryptionKey+
|
||||
transaction.getCreditPhone()+
|
||||
transaction.getAmount();
|
||||
|
||||
String hex = getHash(concat);
|
||||
|
||||
SdkActionDto sdkActionDto = SdkActionDto.builder()
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.phone(transaction.getCreditPhone())
|
||||
.amount(transaction.getAmount().toString())
|
||||
.currency(transaction.getDebitCurrency().toString())
|
||||
.hash(hex)
|
||||
.authType("WEB")
|
||||
.billerReference(transaction.getReference())
|
||||
.action("PAYMENT")
|
||||
.sandbox(true)
|
||||
.paymentProcessorLabel("STEWARD")
|
||||
.responseUrl("https://www.google.com")
|
||||
.build();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Authorization", "Bearer " + token);
|
||||
headers.set("Content-Type", "application/json");
|
||||
|
||||
try {
|
||||
LinkedHashMap response = restService.postAs(url + "/merchant/sdk/action", sdkActionDto, headers, LinkedHashMap.class);
|
||||
logger.info("response: {}", Utils.toJson(response));
|
||||
|
||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||
transaction.setSdkActionId((String) body.get("uid"));
|
||||
|
||||
if(!body.get("status").equals("FAILED")){
|
||||
transaction.setStatus(Status.SUCCESS);
|
||||
transaction.setResponseCode("00");
|
||||
transaction.setTargetUrl((String) body.get("targetUrl"));
|
||||
}else{
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("01");
|
||||
transaction.setErrorMessage((String) body.get("message"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("99");
|
||||
transaction.setErrorMessage("Network error: " + e.getMessage());
|
||||
}
|
||||
|
||||
return transactionService.save(transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object reverse(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poll(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public String getHash(String originalString){
|
||||
String hex = "";
|
||||
MessageDigest digest = null;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] encodedhash = digest.digest(
|
||||
originalString.getBytes(StandardCharsets.UTF_8));
|
||||
hex = bytesToHex(encodedhash);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] hash) {
|
||||
StringBuilder hexString = new StringBuilder(2 * hash.length);
|
||||
for (int i = 0; i < hash.length; i++) {
|
||||
String hex = Integer.toHexString(0xff & hash[i]);
|
||||
if(hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user