hotrecharge integration complete

This commit is contained in:
2026-05-03 23:42:02 +02:00
parent 364128df67
commit d31c8a1e11
14 changed files with 253 additions and 85 deletions

View File

@@ -175,6 +175,14 @@
<artifactId>loki-logback-appender</artifactId> <artifactId>loki-logback-appender</artifactId>
<version>2.0.1</version> <!-- Use the latest version --> <version>2.0.1</version> <!-- Use the latest version -->
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -3,6 +3,7 @@ package zw.qantra.tm;
import io.nflow.rest.config.RestConfiguration; import io.nflow.rest.config.RestConfiguration;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import com.google.gson.Gson; import com.google.gson.Gson;
@@ -10,6 +11,7 @@ import org.springframework.context.annotation.Import;
@SpringBootApplication @SpringBootApplication
@Import(RestConfiguration.class) @Import(RestConfiguration.class)
@EnableCaching
public class TmApplication { public class TmApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@@ -0,0 +1,25 @@
package zw.qantra.tm.config;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("providerProducts");
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(24, TimeUnit.HOURS)
.maximumSize(10000));
return cacheManager;
}
}

View File

@@ -22,7 +22,7 @@ public class ProviderController {
@GetMapping("/{id}/products") @GetMapping("/{id}/products")
public ResponseEntity getProducts(@PathVariable UUID id) { public ResponseEntity getProducts(@PathVariable UUID id) {
return ResponseEntity.ok(providerService.getProviderProducts(id)); return ResponseEntity.ok(providerService.getProviderProducts(id.toString()));
} }
@GetMapping("/{id}/products/{productId}") @GetMapping("/{id}/products/{productId}")

View File

@@ -109,7 +109,7 @@ public class TransactonController {
workflowInstanceService.updateWorkflowInstance(update, action); workflowInstanceService.updateWorkflowInstance(update, action);
CompletableFuture<Object> future = workflowUtils CompletableFuture<Object> future = workflowUtils
.waitForState(transaction.getWorkflowId(), new String[]{"purchaseInvoicePaymentSuccess", "failed"}, .waitForState(transaction.getWorkflowId(), new String[]{"integrationStatusSuccess", "done", "failed"},
15000, 50); 15000, 50);
Object response = future.get(); Object response = future.get();
LogUtils.logPrettyJson(logger, "outgoing transaction", response); LogUtils.logPrettyJson(logger, "outgoing transaction", response);
@@ -139,7 +139,7 @@ public class TransactonController {
workflowInstanceService.updateWorkflowInstance(update, action); workflowInstanceService.updateWorkflowInstance(update, action);
CompletableFuture<Object> future = workflowUtils CompletableFuture<Object> future = workflowUtils
.waitForState(transaction.getWorkflowId(), new String[]{"done", "failed"}, .waitForState(transaction.getWorkflowId(), new String[]{"pollStatusSuccess", "done", "failed"},
15000, 50); 15000, 50);
Object response = future.get(); Object response = future.get();
LogUtils.logPrettyJson(logger, "outgoing transaction", response); LogUtils.logPrettyJson(logger, "outgoing transaction", response);

View File

@@ -21,4 +21,5 @@ public class SBZProductDto {
private BigDecimal defaultAmount; private BigDecimal defaultAmount;
private boolean requiresAmount; private boolean requiresAmount;
private UUID uid; private UUID uid;
private String externalId;
} }

View File

@@ -16,12 +16,17 @@ import org.hibernate.annotations.SQLRestriction;
public class Provider extends BaseEntity { public class Provider extends BaseEntity {
private String clientId; private String clientId;
private String label; private String label;
private String name;
private String description; private String description;
private String externalId; private String externalId;
private String image; private String image;
private String category; private String category;
private String accountFieldName; private String accountFieldName;
private String integrationProcessorLabel; private String integrationProcessorLabel;
private String uid;
private Boolean requiresAmount;
private Boolean requiresPhone;
private Boolean requiresAccount;
private double percentageCommission; private double percentageCommission;
@Column(columnDefinition = "TEXT") @Column(columnDefinition = "TEXT")
private String meta; private String meta;

View File

@@ -3,9 +3,9 @@ package zw.qantra.tm.domain.services;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.WordUtils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -15,28 +15,37 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import zw.qantra.tm.domain.dtos.SBZProductDto; import zw.qantra.tm.domain.dtos.SBZProductDto;
import zw.qantra.tm.domain.models.Provider; import zw.qantra.tm.domain.models.Provider;
import zw.qantra.tm.domain.repositories.ProviderRepository; import zw.qantra.tm.domain.repositories.ProviderRepository;
import zw.qantra.tm.exceptions.ApiException;
import zw.qantra.tm.rest.RestService; import zw.qantra.tm.rest.RestService;
import zw.qantra.tm.utils.Utils;
import java.math.BigDecimal;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j
public class ProviderService { public class ProviderService {
@Getter @Getter
private final ProviderRepository providerRepository; private final ProviderRepository providerRepository;
private final RestService restService; private final RestService restService;
private final HotRechargeTokenService hotRechargeTokenService;
@Value("${hot.api.url:https://ssl.hot.co.zw/api/v3}")
private String hotApiUrl;
@Value("${sbz.aggregator.url}") @Value("${sbz.aggregator.url}")
private String aggregatorUrl; private String aggregatorUrl;
public SBZProductDto getProviderProduct(UUID providerId, UUID productId) { public SBZProductDto getProviderProduct(UUID providerId, UUID productId) {
return getProviderProducts(providerId).stream() return getProviderProducts(providerId.toString()).stream()
.filter(product -> product.getUid().equals(productId)) .filter(product -> product.getUid().equals(productId))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
} }
@Deprecated
public List<SBZProductDto> getProviderProducts(UUID providerId) { public List<SBZProductDto> getProviderProducts(UUID providerId) {
String token = restService.getMerchantToken(); String token = restService.getMerchantToken();
@@ -64,6 +73,74 @@ public class ProviderService {
return products; return products;
} }
@Cacheable(value = "providerProducts", key = "#providerId")
public List<SBZProductDto> getProviderProducts(String providerId) {
try {
Provider provider = providerRepository.findByClientId(providerId);
if (provider == null) {
return Collections.emptyList();
}
String stockUrl = hotApiUrl + "/query/stock/" + 111;
HttpHeaders headers = new HttpHeaders();
String token = hotRechargeTokenService.getToken();
headers.setBearerAuth(token);
LinkedHashMap<String, Object> response = restService.getAs(stockUrl, headers, LinkedHashMap.class);
List stock = (List) response.get("stock");
List<SBZProductDto> products = new ArrayList<>();
for (Object item : stock) {
LinkedHashMap<String, Object> stockItem = (LinkedHashMap<String, Object>) item;
String stockProviderId = (String) stockItem.get("providerId");
if (stockProviderId.equals(providerId)) {
log.info("Found matching provider in stock: " + stockItem);
SBZProductDto sbzProductDto = new SBZProductDto();
sbzProductDto.setName((String) stockItem.get("name"));
sbzProductDto.setDescription((String) stockItem.get("description"));
sbzProductDto.setDisplayName((String) stockItem.get("name"));
sbzProductDto.setDefaultAmount(new BigDecimal(stockItem.get("amount").toString()));
sbzProductDto.setRequiresAmount(true); // always true for now
sbzProductDto.setUid(UUID.fromString(Utils.getUid()));
sbzProductDto.setExternalId((String) stockItem.get("productCode"));
products.add(sbzProductDto);
}
}
return products;
} catch (IllegalArgumentException e) {
return Collections.emptyList();
}
}
public String getProviderId(String billClientId) {
Provider provider = getProviderRepository()
.findByClientId(billClientId);
if(provider == null){
throw new ApiException("Provider not found for billClientId: " + billClientId);
}
@SuppressWarnings("unchecked")
Map<String, String> meta = Utils.fromJson(provider.getMeta(), Map.class);
return meta.get("hotProductId");
}
public String getExternalId(String providerId, String productUuid) {
try {
UUID productUid = UUID.fromString(productUuid);
List<SBZProductDto> products = getProviderProducts(providerId);
return products.stream()
.filter(product -> product.getUid().equals(productUid))
.map(SBZProductDto::getExternalId)
.findFirst()
.orElse(null);
} catch (IllegalArgumentException e) {
log.error("Invalid UUID format: " + productUuid, e);
return null;
}
}
public Object getProviderByClientId(String clientId) { public Object getProviderByClientId(String clientId) {
Provider provider = providerRepository.findByClientId(clientId); Provider provider = providerRepository.findByClientId(clientId);
if (provider != null) { if (provider != null) {
@@ -81,7 +158,7 @@ public class ProviderService {
existingProviders = getProviderRepository().findAll(); existingProviders = getProviderRepository().findAll();
} }
return getProviders(existingProviders); return existingProviders;
} }
public Object getProviders(List<Provider> existingProviders) { public Object getProviders(List<Provider> existingProviders) {

View File

@@ -1,29 +1,17 @@
package zw.qantra.tm.domain.services.processors.confirmations.hotrecharge; package zw.qantra.tm.domain.services.processors.confirmations.hotrecharge;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import zw.qantra.tm.domain.enums.Status; import zw.qantra.tm.domain.services.AdditionalDataService;
import zw.qantra.tm.domain.models.Transaction; import zw.qantra.tm.domain.services.HotRechargeTokenService;
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface; import zw.qantra.tm.rest.RestService;
@Service("CONFIRM_ECONET_BUNDLES_HOT") @Service("CONFIRM_ECONET_BUNDLES_HOT")
@RequiredArgsConstructor public class EconetBundlesConfirmationHotProcessor extends NetoneConfirmationHotProcessor {
public class EconetBundlesConfirmationHotProcessor implements TransactionProcessorInterface { public EconetBundlesConfirmationHotProcessor(
@Override AdditionalDataService additionalDataService,
public Object process(Transaction transaction) throws Exception { HotRechargeTokenService hotRechargeTokenService,
transaction.setStatus(Status.SUCCESS); RestService restService) {
transaction.setResponseCode("00"); super(additionalDataService, hotRechargeTokenService, restService);
return transaction;
}
@Override
public Object reverse(Transaction transaction) {
return transaction;
}
@Override
public Object poll(Transaction transaction) throws Exception {
return transaction;
} }
} }

View File

@@ -1,29 +1,17 @@
package zw.qantra.tm.domain.services.processors.confirmations.hotrecharge; package zw.qantra.tm.domain.services.processors.confirmations.hotrecharge;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import zw.qantra.tm.domain.enums.Status; import zw.qantra.tm.domain.services.AdditionalDataService;
import zw.qantra.tm.domain.models.Transaction; import zw.qantra.tm.domain.services.HotRechargeTokenService;
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface; import zw.qantra.tm.rest.RestService;
@Service("CONFIRM_ECONET_HOT") @Service("CONFIRM_ECONET_HOT")
@RequiredArgsConstructor public class EconetConfirmationHotProcessor extends NetoneConfirmationHotProcessor {
public class EconetConfirmationHotProcessor implements TransactionProcessorInterface { public EconetConfirmationHotProcessor(
@Override AdditionalDataService additionalDataService,
public Object process(Transaction transaction) throws Exception { HotRechargeTokenService hotRechargeTokenService,
transaction.setStatus(Status.SUCCESS); RestService restService) {
transaction.setResponseCode("00"); super(additionalDataService, hotRechargeTokenService, restService);
return transaction;
}
@Override
public Object reverse(Transaction transaction) {
return transaction;
}
@Override
public Object poll(Transaction transaction) throws Exception {
return transaction;
} }
} }

View File

@@ -1,19 +1,68 @@
package zw.qantra.tm.domain.services.processors.confirmations.hotrecharge; package zw.qantra.tm.domain.services.processors.confirmations.hotrecharge;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import zw.qantra.tm.domain.enums.RequestType;
import zw.qantra.tm.domain.enums.Status; 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.models.Transaction;
import zw.qantra.tm.domain.services.AdditionalDataService;
import zw.qantra.tm.domain.services.HotRechargeTokenService;
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface; 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.util.*;
@Service("CONFIRM_NETONE_HOT") @Service("CONFIRM_NETONE_HOT")
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j
public class NetoneConfirmationHotProcessor implements TransactionProcessorInterface { public class NetoneConfirmationHotProcessor implements TransactionProcessorInterface {
private final AdditionalDataService additionalDataService;
private final HotRechargeTokenService hotRechargeTokenService;
private final RestService restService;
@Value("${hot.api.url:https://ssl.hot.co.zw/api/v3}")
private String hotApiUrl;
@Override @Override
public Object process(Transaction transaction) throws Exception { public Object process(Transaction transaction) throws Exception {
String token = hotRechargeTokenService.getToken();
if (!checkBalance(token, transaction.getAmount())) {
transaction.setStatus(Status.FAILED);
transaction.setResponseCode("92");
transaction.setErrorMessage("There's a technical issue on our end. Please try again later.");
return transaction;
}
transaction.setStatus(Status.SUCCESS); transaction.setStatus(Status.SUCCESS);
transaction.setResponseCode("00"); transaction.setResponseCode("00");
List<Map> additionalDataList = new ArrayList<>();
additionalDataList.add(new HashMap() {{
put("name", "Provider");
put("value", transaction.getBillName());
}});
additionalDataList.add(new HashMap() {{
put("name", "Destination Phone Number");
put("value", transaction.getCreditAccount());
}});
transaction.setAdditionalData(additionalDataList);
AdditionalData additionalData = AdditionalData.builder()
.transactionId(transaction.getId().toString())
.requestType(RequestType.CONFIRM)
.jsonString(Utils.toJson(additionalDataList))
.build();
additionalDataService.getAdditionalDataRepository().save(additionalData);
return transaction; return transaction;
} }
@@ -26,4 +75,27 @@ public class NetoneConfirmationHotProcessor implements TransactionProcessorInter
public Object poll(Transaction transaction) throws Exception { public Object poll(Transaction transaction) throws Exception {
return transaction; return transaction;
} }
private boolean checkBalance(String token, BigDecimal amount) {
try {
String balanceUrl = hotApiUrl + "/account/balance/4";
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(token);
LinkedList responseEntity = restService.getAs(balanceUrl, headers, LinkedList.class);
LinkedHashMap response = (LinkedHashMap) responseEntity.get(0);
log.info("Response: {}", response);
if (response != null && response.containsKey("balance")) {
Object balance = response.get("balance");
log.info("Current balance: {}", balance);
return (new BigDecimal(balance.toString())).compareTo(amount) > 0;
}
return false;
} catch (Exception e) {
log.error("Failed to check balance: {}", e.getMessage(), e);
return false;
}
}
} }

View File

@@ -52,8 +52,8 @@ public class ZesaConfirmationHotProcessor implements TransactionProcessorInterfa
if (!checkBalance(token, transaction.getAmount())) { if (!checkBalance(token, transaction.getAmount())) {
transaction.setStatus(Status.FAILED); transaction.setStatus(Status.FAILED);
transaction.setResponseCode("91"); transaction.setResponseCode("92");
transaction.setErrorMessage("Insufficient balance"); transaction.setErrorMessage("There's a technical issue on our end. Please try again later.");
return transaction; return transaction;
} }
@@ -91,12 +91,12 @@ public class ZesaConfirmationHotProcessor implements TransactionProcessorInterfa
private List<Map<String, String>> buildAdditionalData(Map<String, Object> customerData) { private List<Map<String, String>> buildAdditionalData(Map<String, Object> customerData) {
List<Map<String, String>> additionalDataList = new ArrayList<>(); List<Map<String, String>> additionalDataList = new ArrayList<>();
if (customerData != null) { if (customerData != null) {
additionalDataList.add(Map.of("key", "accountNumber", additionalDataList.add(Map.of("name", "MeterNumber",
"value", customerData.getOrDefault("accountNumber", "").toString())); "value", customerData.getOrDefault("accountNumber", "").toString()));
Map<String, Object> details = (Map<String, Object>) customerData.get("details"); Map<String, Object> details = (Map<String, Object>) customerData.get("details");
if (details != null) { if (details != null) {
for (Map.Entry<String, Object> entry : details.entrySet()) { for (Map.Entry<String, Object> entry : details.entrySet()) {
additionalDataList.add(Map.of("key", entry.getKey(), "value", entry.getValue().toString())); additionalDataList.add(Map.of("name", entry.getKey(), "value", entry.getValue().toString()));
} }
} }
} }

View File

@@ -13,11 +13,9 @@ import org.springframework.web.client.ResourceAccessException;
import zw.qantra.tm.domain.enums.RequestType; import zw.qantra.tm.domain.enums.RequestType;
import zw.qantra.tm.domain.enums.Status; import zw.qantra.tm.domain.enums.Status;
import zw.qantra.tm.domain.models.AdditionalData; import zw.qantra.tm.domain.models.AdditionalData;
import zw.qantra.tm.domain.models.Provider;
import zw.qantra.tm.domain.models.Transaction; import zw.qantra.tm.domain.models.Transaction;
import zw.qantra.tm.domain.services.*; import zw.qantra.tm.domain.services.*;
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface; import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
import zw.qantra.tm.exceptions.ApiException;
import zw.qantra.tm.rest.RestService; import zw.qantra.tm.rest.RestService;
import zw.qantra.tm.utils.Utils; import zw.qantra.tm.utils.Utils;
@@ -73,8 +71,8 @@ public class HotRechargeIntegrationProcessor implements TransactionProcessorInte
if (!checkBalance(token, transaction.getAmount())) { if (!checkBalance(token, transaction.getAmount())) {
transaction.setStatus(Status.FAILED); transaction.setStatus(Status.FAILED);
transaction.setResponseCode("91"); transaction.setResponseCode("92");
transaction.setErrorMessage("Insufficient balance"); transaction.setErrorMessage("There's a technical issue on our end. Please try again later.");
return transaction; return transaction;
} }
@@ -155,17 +153,18 @@ public class HotRechargeIntegrationProcessor implements TransactionProcessorInte
Map<String, Object> request = new LinkedHashMap<>(); Map<String, Object> request = new LinkedHashMap<>();
request.put("AgentReference", UUID.randomUUID().toString()); request.put("AgentReference", UUID.randomUUID().toString());
request.put("ProductId", getProductId(transaction.getBillClientId())); request.put("ProductId", providerService.getProviderId(transaction.getBillClientId()));
request.put("Target", transaction.getCreditAccount()); request.put("Target", transaction.getCreditAccount());
request.put("Amount", transaction.getAmount()); request.put("Amount", transaction.getAmount());
if(getProductId(transaction.getBillClientId()).equals("41")) { // do this for zesa
if(providerService.getProviderId(transaction.getBillClientId()).equals("41")) {
List<Map<String, String>> rechargeOptions = new ArrayList<>(); List<Map<String, String>> rechargeOptions = new ArrayList<>();
if (transaction.getCreditPhone() != null) { if (transaction.getDebitPhone() != null) {
Map<String, String> option = new LinkedHashMap<>(); Map<String, String> option = new LinkedHashMap<>();
option.put("Name", "NotifyNumber"); option.put("Name", "NotifyNumber");
option.put("ParameterType", "String"); option.put("ParameterType", "String");
option.put("Value", transaction.getCreditPhone()); option.put("Value", transaction.getDebitPhone());
rechargeOptions.add(option); rechargeOptions.add(option);
} }
if (!rechargeOptions.isEmpty()) { if (!rechargeOptions.isEmpty()) {
@@ -173,6 +172,18 @@ public class HotRechargeIntegrationProcessor implements TransactionProcessorInte
} }
} }
// do this for Econet bundles
if(providerService.getProviderId(transaction.getBillClientId()).equals("111")) {
String productCode = providerService.getExternalId(
providerService.getProviderId(transaction.getBillClientId()), transaction.getProductUid());
List<Map<String, String>> rechargeOptions = new ArrayList<>();
Map<String, String> option = new LinkedHashMap<>();
option.put("Name", "ProductCode");
option.put("ParameterType", "String");
option.put("Value", productCode);
rechargeOptions.add(option);
}
logger.info("Sending recharge request: {}", request); logger.info("Sending recharge request: {}", request);
ResponseEntity<?> response = restService.postAsEntity(rechargeUrl, request, headers, LinkedHashMap.class); ResponseEntity<?> response = restService.postAsEntity(rechargeUrl, request, headers, LinkedHashMap.class);
logger.info("Recharge response: {}", response.getBody()); logger.info("Recharge response: {}", response.getBody());
@@ -213,25 +224,16 @@ public class HotRechargeIntegrationProcessor implements TransactionProcessorInte
private List<Map<String, String>> buildAdditionalDataList(Map<String, Object> rechargeData) { private List<Map<String, String>> buildAdditionalDataList(Map<String, Object> rechargeData) {
List<Map<String, String>> additionalDataList = new ArrayList<>(); List<Map<String, String>> additionalDataList = new ArrayList<>();
for (Map.Entry<String, Object> entry : rechargeData.entrySet()) { for (Map.Entry<String, Object> entry : rechargeData.entrySet()) {
if(entry.getKey().equals("Cost"))
continue;
Map<String, String> dataItem = new LinkedHashMap<>(); Map<String, String> dataItem = new LinkedHashMap<>();
dataItem.put("key", entry.getKey()); dataItem.put("name", entry.getKey());
dataItem.put("value", entry.getValue().toString()); dataItem.put("value", entry.getValue().toString());
additionalDataList.add(dataItem); additionalDataList.add(dataItem);
} }
return additionalDataList; return additionalDataList;
} }
private String getProductId(String billClientId) {
Provider provider = providerService.getProviderRepository()
.findByClientId(billClientId);
if(provider == null){
throw new ApiException("Provider not found for billClientId: " + billClientId);
}
@SuppressWarnings("unchecked")
Map<String, String> meta = Utils.fromJson(provider.getMeta(), Map.class);
return meta.get("hotProductId");
}
@Override @Override
public Object reverse(Transaction transaction) { public Object reverse(Transaction transaction) {
return transaction; return transaction;

View File

@@ -42,6 +42,15 @@ public class EcocashRemotePaymentProcessor implements TransactionProcessorInterf
@Override @Override
public Object process(Transaction transaction) throws Exception { public Object process(Transaction transaction) throws Exception {
logger.info("processing transaction"); logger.info("processing transaction");
if(settingService.getBooleanSetting("SIMULATE_ECOCASH_SUCCESS")) {
transaction.setStatus(Status.SUCCESS);
transaction.setResponseCode("00");
transaction.setPaymentProcessorRef(RandomStringUtils.randomNumeric(10));
transaction.setDebitRef(RandomStringUtils.randomNumeric(10));
return transaction;
}
String token = restService.getMerchantToken(); String token = restService.getMerchantToken();
// send total less gateway charges // send total less gateway charges
@@ -83,15 +92,6 @@ public class EcocashRemotePaymentProcessor implements TransactionProcessorInterf
LinkedHashMap body = (LinkedHashMap) response.get("body"); LinkedHashMap body = (LinkedHashMap) response.get("body");
transaction.setSdkActionId((String) body.get("uid")); transaction.setSdkActionId((String) body.get("uid"));
// todo: REMOVE THIS
if(settingService.getBooleanSetting("SIMULATE_ECOCASH_SUCCESS")){
body.put("status", "SUCCESS");
LinkedHashMap hashMap = new LinkedHashMap();
hashMap.put("debitReference", RandomStringUtils.randomNumeric(10));
body.put("transaction", hashMap);
body.put("targetUrl", "/home");
}
if(body.get("status").equals("SUCCESS")){ if(body.get("status").equals("SUCCESS")){
transaction.setStatus(Status.SUCCESS); transaction.setStatus(Status.SUCCESS);
transaction.setResponseCode("00"); transaction.setResponseCode("00");