velocity integration complete
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
package zw.qantra.tm.domain.controllers;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.kaczmarzyk.spring.data.jpa.domain.Equal;
|
||||
import net.kaczmarzyk.spring.data.jpa.web.annotation.And;
|
||||
import net.kaczmarzyk.spring.data.jpa.web.annotation.Spec;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import zw.qantra.tm.domain.models.Provider;
|
||||
@@ -16,8 +21,11 @@ public class ProviderController {
|
||||
private final ProviderService providerService;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity getProviders(@RequestParam(required = false) String category) {
|
||||
return ResponseEntity.ok(providerService.getProvidersByCategory(category));
|
||||
public ResponseEntity getProviders(
|
||||
@And({
|
||||
@Spec(path = "category", spec = Equal.class)
|
||||
}) Specification<Provider> spec, Pageable pageable) {
|
||||
return ResponseEntity.ok(providerService.findAll(spec, pageable));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/products")
|
||||
|
||||
@@ -30,4 +30,5 @@ public class Provider extends BaseEntity {
|
||||
private double percentageCommission;
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String meta;
|
||||
private Integer priority;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package zw.qantra.tm.domain.repositories;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import zw.qantra.tm.domain.models.Provider;
|
||||
|
||||
@@ -8,7 +9,7 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface ProviderRepository extends JpaRepository<Provider, UUID> {
|
||||
public interface ProviderRepository extends JpaRepository<Provider, UUID>, JpaSpecificationExecutor<Provider> {
|
||||
List<Provider> findByCategory(String category);
|
||||
Provider findByClientId(String clientId);
|
||||
boolean existsByClientId(String clientId);
|
||||
|
||||
@@ -26,31 +26,62 @@ public class HotRechargeTokenService {
|
||||
private String hotAccessCode;
|
||||
@Value("${hot.password}")
|
||||
private String hotPassword;
|
||||
@Value("${hot.token.expiry.minutes:25}")
|
||||
private int tokenExpiryMinutes;
|
||||
@Value("${hot.cache.duration.minutes:5}")
|
||||
private int cacheDurationMinutes;
|
||||
|
||||
private String cachedToken;
|
||||
private long tokenExpiryTime;
|
||||
private String cachedRefreshToken;
|
||||
private long cacheExpiryTime;
|
||||
|
||||
public synchronized String getToken() {
|
||||
if (isTokenValid()) {
|
||||
logger.info("Returning cached HotRecharge token");
|
||||
return cachedToken;
|
||||
if (isCacheValid()) {
|
||||
logger.info("Cache is valid, attempting token refresh");
|
||||
return refreshCachedToken();
|
||||
}
|
||||
return fetchNewToken();
|
||||
}
|
||||
|
||||
private boolean isTokenValid() {
|
||||
return cachedToken != null && System.currentTimeMillis() < tokenExpiryTime;
|
||||
private boolean isCacheValid() {
|
||||
return cachedToken != null && cachedRefreshToken != null && System.currentTimeMillis() < cacheExpiryTime;
|
||||
}
|
||||
|
||||
private synchronized String fetchNewToken() {
|
||||
if (isTokenValid()) {
|
||||
return cachedToken;
|
||||
private synchronized String refreshCachedToken() {
|
||||
if (!isCacheValid()) {
|
||||
return fetchNewToken();
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info("Fetching new HotRecharge token");
|
||||
logger.info("Refreshing HotRecharge token via refresh endpoint");
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
|
||||
Map<String, String> payload = Map.of(
|
||||
"token", cachedToken,
|
||||
"refreshToken", cachedRefreshToken
|
||||
);
|
||||
|
||||
LinkedHashMap<String, Object> response = restService.postAs(hotAuthUrl + "/identity/refresh", payload, headers, LinkedHashMap.class);
|
||||
cachedToken = (String) response.get("token");
|
||||
cachedRefreshToken = (String) response.get("refreshToken");
|
||||
cacheExpiryTime = System.currentTimeMillis() + (cacheDurationMinutes * 60 * 1000L);
|
||||
|
||||
logger.info("HotRecharge token refreshed via refresh endpoint, cache extended by {} minutes", cacheDurationMinutes);
|
||||
return cachedToken;
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to refresh HotRecharge token: " + e.getMessage(), e);
|
||||
// Fall back to login on refresh failure
|
||||
return fetchNewToken();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized String fetchNewToken() {
|
||||
if (isCacheValid()) {
|
||||
return refreshCachedToken();
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info("Fetching new HotRecharge token via login");
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
@@ -62,13 +93,15 @@ public class HotRechargeTokenService {
|
||||
|
||||
LinkedHashMap<String, Object> response = restService.postAs(hotAuthUrl + "/identity/login", payload, headers, LinkedHashMap.class);
|
||||
cachedToken = (String) response.get("token");
|
||||
tokenExpiryTime = System.currentTimeMillis() + (tokenExpiryMinutes * 60 * 1000L);
|
||||
cachedRefreshToken = (String) response.get("refreshToken");
|
||||
cacheExpiryTime = System.currentTimeMillis() + (cacheDurationMinutes * 60 * 1000L);
|
||||
|
||||
logger.info("New HotRecharge token cached, expires in {} minutes", tokenExpiryMinutes);
|
||||
logger.info("New HotRecharge token cached, cache expires in {} minutes", cacheDurationMinutes);
|
||||
return cachedToken;
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to fetch HotRecharge token: " + e.getMessage(), e);
|
||||
cachedToken = null;
|
||||
cachedRefreshToken = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -76,7 +109,7 @@ public class HotRechargeTokenService {
|
||||
public synchronized void invalidateToken() {
|
||||
logger.info("Invalidating cached HotRecharge token");
|
||||
cachedToken = null;
|
||||
tokenExpiryTime = 0;
|
||||
cachedRefreshToken = null;
|
||||
cacheExpiryTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -164,16 +166,8 @@ public class ProviderService {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getProvidersByCategory(String category) {
|
||||
|
||||
List<Provider> existingProviders;
|
||||
if (category != null && !category.isEmpty()) {
|
||||
existingProviders = getProviderRepository().findByCategory(category);
|
||||
} else {
|
||||
existingProviders = getProviderRepository().findAll();
|
||||
}
|
||||
|
||||
return existingProviders;
|
||||
public Object findAll(Specification<Provider> specification, Pageable pageable) {
|
||||
return getProviderRepository().findAll(specification, pageable);
|
||||
}
|
||||
|
||||
public Object getProviders(List<Provider> existingProviders) {
|
||||
|
||||
@@ -181,7 +181,10 @@ public class VelocityPaymentService {
|
||||
transaction.setTargetUrl(redirectUrl);
|
||||
return transaction;
|
||||
}
|
||||
return null;
|
||||
|
||||
String errorMessage = (String) body.get("errorMessage");
|
||||
log.error("Unexpected transaction response from Velocity: {}", response);
|
||||
throw new IllegalStateException(errorMessage);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Error initiating payment: {}", e.getMessage(), e);
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.services.AdditionalDataService;
|
||||
import zw.qantra.tm.domain.services.HotRechargeBalanceService;
|
||||
import zw.qantra.tm.domain.services.HotRechargeTokenService;
|
||||
import zw.qantra.tm.domain.services.SettingService;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
|
||||
|
||||
@@ -13,7 +14,8 @@ public class EconetBundlesConfirmationHotProcessor extends NetoneConfirmationHot
|
||||
AdditionalDataService additionalDataService,
|
||||
HotRechargeTokenService hotRechargeTokenService,
|
||||
HotRechargeBalanceService hotRechargeBalanceService,
|
||||
RestService restService) {
|
||||
super(additionalDataService, hotRechargeTokenService, hotRechargeBalanceService, restService);
|
||||
RestService restService,
|
||||
SettingService settingService) {
|
||||
super(additionalDataService, hotRechargeTokenService, hotRechargeBalanceService, restService, settingService);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.services.AdditionalDataService;
|
||||
import zw.qantra.tm.domain.services.HotRechargeBalanceService;
|
||||
import zw.qantra.tm.domain.services.HotRechargeTokenService;
|
||||
import zw.qantra.tm.domain.services.SettingService;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
|
||||
|
||||
@@ -13,7 +14,8 @@ public class EconetConfirmationHotProcessor extends NetoneConfirmationHotProcess
|
||||
AdditionalDataService additionalDataService,
|
||||
HotRechargeTokenService hotRechargeTokenService,
|
||||
HotRechargeBalanceService hotRechargeBalanceService,
|
||||
RestService restService) {
|
||||
super(additionalDataService, hotRechargeTokenService, hotRechargeBalanceService, restService);
|
||||
RestService restService,
|
||||
SettingService settingService) {
|
||||
super(additionalDataService, hotRechargeTokenService, hotRechargeBalanceService, restService, settingService);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.AdditionalDataService;
|
||||
import zw.qantra.tm.domain.services.HotRechargeBalanceService;
|
||||
import zw.qantra.tm.domain.services.HotRechargeTokenService;
|
||||
import zw.qantra.tm.domain.services.SettingService;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
@@ -28,6 +29,7 @@ public class NetoneConfirmationHotProcessor implements TransactionProcessorInter
|
||||
protected final HotRechargeTokenService hotRechargeTokenService;
|
||||
protected final HotRechargeBalanceService hotRechargeBalanceService;
|
||||
protected final RestService restService;
|
||||
protected final SettingService settingService;
|
||||
|
||||
@Value("${hot.api.url:https://ssl.hot.co.zw/api/v3}")
|
||||
private String hotApiUrl;
|
||||
@@ -36,14 +38,18 @@ public class NetoneConfirmationHotProcessor implements TransactionProcessorInter
|
||||
@Override
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
|
||||
String token = hotRechargeTokenService.getToken();
|
||||
if (!hotRechargeBalanceService.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;
|
||||
// do this if we not simulating success, if simulating success, we skip balance check and just return success
|
||||
if(!settingService.getBooleanSetting("SIMULATE_HOT_SUCCESS")){
|
||||
String token = hotRechargeTokenService.getToken();
|
||||
if (!hotRechargeBalanceService.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.setCreditAccount(Utils.formatPhoneNumber(transaction.getCreditAccount(), "ZW"));
|
||||
transaction.setStatus(Status.SUCCESS);
|
||||
transaction.setResponseCode("00");
|
||||
|
||||
|
||||
@@ -13,10 +13,7 @@ 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.Transaction;
|
||||
import zw.qantra.tm.domain.services.AdditionalDataService;
|
||||
import zw.qantra.tm.domain.services.HotRechargeBalanceService;
|
||||
import zw.qantra.tm.domain.services.HotRechargeTokenService;
|
||||
import zw.qantra.tm.domain.services.ProviderService;
|
||||
import zw.qantra.tm.domain.services.*;
|
||||
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.exceptions.ApiException;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
@@ -35,6 +32,7 @@ public class ZesaConfirmationHotProcessor implements TransactionProcessorInterfa
|
||||
private final ProviderService providerService;
|
||||
private final HotRechargeTokenService hotRechargeTokenService;
|
||||
private final HotRechargeBalanceService hotRechargeBalanceService;
|
||||
private final SettingService settingService;
|
||||
|
||||
@Value("${hot.api.url:https://ssl.hot.co.zw/api/v3}")
|
||||
private String hotApiUrl;
|
||||
@@ -44,6 +42,13 @@ public class ZesaConfirmationHotProcessor implements TransactionProcessorInterfa
|
||||
logger.info("Processing ZESA confirmation from HotRecharge");
|
||||
|
||||
try {
|
||||
// do this if we not simulating success, if simulating success, we skip balance check and just return success
|
||||
if(settingService.getBooleanSetting("SIMULATE_HOT_SUCCESS")){
|
||||
transaction.setStatus(Status.SUCCESS);
|
||||
transaction.setResponseCode("00");
|
||||
return transaction;
|
||||
}
|
||||
|
||||
String token = hotRechargeTokenService.getToken();
|
||||
if (token == null || token.isEmpty()) {
|
||||
transaction.setStatus(Status.FAILED);
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
public interface LogicHandler<I, O> {
|
||||
O process(I input);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,16 @@
|
||||
package zw.qantra.tm.domain.services.processors.payments;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.SettingService;
|
||||
|
||||
@@ -30,6 +30,7 @@ import zw.qantra.tm.exceptions.AlreadyExistsException;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
@@ -99,16 +100,7 @@ public class RegistrationWorkflow extends WorkflowDefinition {
|
||||
}
|
||||
|
||||
// update phone number format
|
||||
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
|
||||
try {
|
||||
String phone = payload.getPhone();
|
||||
Phonenumber.PhoneNumber zimProto = phoneUtil.parse(phone, "ZW");
|
||||
phone = zimProto.getCountryCode() + String.valueOf(zimProto.getNationalNumber());
|
||||
payload.setPhone(phone.replaceAll("[^0-9]", ""));
|
||||
} catch (NumberParseException e) {
|
||||
System.err.println("NumberParseException was thrown: " + e.toString());
|
||||
return NextAction.moveToState(FAILED, "Invalid phone number");
|
||||
}
|
||||
payload.setPhone(Utils.formatPhoneNumber(payload.getPhone(), "ZW"));
|
||||
|
||||
execution.setVariable("registerRequest", payload);
|
||||
execution.setVariable("body", payload);
|
||||
|
||||
@@ -77,24 +77,11 @@ public class CleanupHandler implements HandlerInterface {
|
||||
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
|
||||
|
||||
if(debitPhoneNumber != null && !debitPhoneNumber.isEmpty()){
|
||||
try {
|
||||
// phone must begin with '+'
|
||||
Phonenumber.PhoneNumber zimPhoneNumber = phoneUtil.parse(debitPhoneNumber, "");
|
||||
String formattedPhoneNumber = phoneUtil.format(zimPhoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
transaction.setDebitPhone(formattedPhoneNumber.replaceAll("[^0-9]", ""));
|
||||
} catch (NumberParseException e) {
|
||||
System.err.println("NumberParseException was thrown: " + e.toString());
|
||||
}
|
||||
transaction.setDebitPhone(Utils.formatPhoneNumber(debitPhoneNumber, ""));
|
||||
}
|
||||
|
||||
if(creditPhoneNumber != null && !creditPhoneNumber.isEmpty()){
|
||||
try {
|
||||
Phonenumber.PhoneNumber zimPhoneNumber = phoneUtil.parse(creditPhoneNumber, "ZW");
|
||||
String formattedPhoneNumber = phoneUtil.format(zimPhoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
transaction.setCreditPhone(formattedPhoneNumber.replaceAll("[^0-9]", ""));
|
||||
} catch (NumberParseException e) {
|
||||
System.err.println("NumberParseException was thrown: " + e.toString());
|
||||
}
|
||||
transaction.setDebitPhone(Utils.formatPhoneNumber(creditPhoneNumber, "ZW"));
|
||||
}
|
||||
|
||||
return transaction;
|
||||
|
||||
@@ -24,7 +24,7 @@ public class RecipientsUpdateHandler implements HandlerInterface {
|
||||
List<Recipient> recipients = recipientService.getRecipient(transaction.getCreditAccount(), transaction.getUserId());
|
||||
|
||||
Recipient recipient = null;
|
||||
if(recipients.size() > 0){
|
||||
if(!recipients.isEmpty()){
|
||||
recipient = recipients.get(0);
|
||||
}else{
|
||||
recipient = new Recipient();
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package zw.qantra.tm.rest;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RestTemplateInterceptor
|
||||
implements ClientHttpRequestInterceptor {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass().getName());
|
||||
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(
|
||||
HttpRequest request,
|
||||
byte[] reqBody,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
String requestBody = new String(reqBody, StandardCharsets.UTF_8);
|
||||
if(!isJSONValid(requestBody)) requestBody = toBasicJson(requestBody);
|
||||
|
||||
logger.info("Request Headers: {}", request.getHeaders().toString());
|
||||
|
||||
// we don't log file data
|
||||
if(request.getHeaders().getContentLength() < 10000){
|
||||
logger.info("Request: {}: {}\n{}",
|
||||
request.getMethod(),
|
||||
request.getURI(),
|
||||
gson.toJson(gson.fromJson(requestBody, HashMap.class)));
|
||||
}
|
||||
ClientHttpResponse response = execution.execute(request, reqBody);
|
||||
InputStreamReader isr = new InputStreamReader(response.getBody());
|
||||
String body = new BufferedReader(isr).lines()
|
||||
.collect(Collectors.joining("\n"));
|
||||
try{
|
||||
logger.info("Response body:\n{}", gson.toJson(gson.fromJson(body, HashMap.class)));
|
||||
}catch (Exception exception){
|
||||
logger.info("Problem serializing resp: {}", exception.getMessage());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public String toBasicJson(String string){
|
||||
HashMap map = new HashMap();
|
||||
map.put("log", string);
|
||||
return gson.toJson(map);
|
||||
}
|
||||
|
||||
public boolean isJSONValid(String test) {
|
||||
try {
|
||||
new JSONObject(test);
|
||||
} catch (JSONException ex) {
|
||||
try {
|
||||
new JSONArray(test);
|
||||
} catch (JSONException ex1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -36,9 +36,11 @@ public class ProviderSeeder implements Seeder {
|
||||
.integrationProcessorLabel("HOT")
|
||||
.accountFieldName("Phone Number")
|
||||
.percentageCommission(5)
|
||||
.requiresAccount(true)
|
||||
.requiresAccount(false)
|
||||
.requiresAmount(true)
|
||||
.requiresPhone(true)
|
||||
.priority(2)
|
||||
.meta("{\"hotProductId\": \"101\"}")
|
||||
.uid(Utils.getUid())
|
||||
.build(),
|
||||
Provider.builder()
|
||||
@@ -52,10 +54,12 @@ public class ProviderSeeder implements Seeder {
|
||||
.integrationProcessorLabel("HOT")
|
||||
.accountFieldName("Phone Number")
|
||||
.percentageCommission(5)
|
||||
.requiresAccount(true)
|
||||
.requiresAccount(false)
|
||||
.requiresAmount(true)
|
||||
.requiresPhone(true)
|
||||
.uid(Utils.getUid())
|
||||
.priority(3)
|
||||
.meta("{\"hotProductId\": \"35\"}")
|
||||
.build(),
|
||||
Provider.builder()
|
||||
.name("Zesa Prepaid")
|
||||
@@ -71,6 +75,8 @@ public class ProviderSeeder implements Seeder {
|
||||
.requiresAccount(true)
|
||||
.requiresAmount(true)
|
||||
.requiresPhone(true)
|
||||
.priority(1)
|
||||
.meta("{\"hotProductId\": \"41\"}")
|
||||
.uid(Utils.getUid())
|
||||
.build(),
|
||||
Provider.builder()
|
||||
@@ -84,9 +90,11 @@ public class ProviderSeeder implements Seeder {
|
||||
.integrationProcessorLabel("HOT")
|
||||
.accountFieldName("Phone Number")
|
||||
.percentageCommission(5)
|
||||
.requiresAccount(true)
|
||||
.requiresAccount(false)
|
||||
.requiresAmount(false)
|
||||
.requiresPhone(true)
|
||||
.priority(4)
|
||||
.meta("{\"hotProductId\": \"111\"}")
|
||||
.uid(Utils.getUid())
|
||||
.build()
|
||||
);
|
||||
|
||||
@@ -7,12 +7,31 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.util.StdDateFormat;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.google.i18n.phonenumbers.NumberParseException;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.Phonenumber;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Utils {
|
||||
|
||||
public static String formatPhoneNumber(String phoneNumber, String region) {
|
||||
if (phoneNumber == null || phoneNumber.isEmpty()) {
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
|
||||
try {
|
||||
Phonenumber.PhoneNumber numberProto = phoneUtil.parse(phoneNumber, region);
|
||||
return phoneUtil.format(numberProto, PhoneNumberUtil.PhoneNumberFormat.E164)
|
||||
.replaceAll("[^0-9]", "");
|
||||
} catch (NumberParseException e) {
|
||||
return phoneNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T deepCopy(Object object, Class<T> clazz) {
|
||||
String json = toJson(object);
|
||||
return fromJson(json, clazz);
|
||||
|
||||
@@ -35,7 +35,7 @@ jwt.secret=your-super-secret-jwt-key-here-make-it-very-long-and-secure-in-produc
|
||||
jwt.expiration=86400000
|
||||
|
||||
logging.level.root=WARN
|
||||
spring.datasource.nflow.url=jdbc:postgresql://62.171.179.108:5432/nflow
|
||||
spring.datasource.nflow.url=jdbc:postgresql://62.171.179.108:5432/qpay-nflow
|
||||
spring.datasource.nflow.username=postgres
|
||||
spring.datasource.nflow.password=zdDZMzq6F4B4L1IUla
|
||||
spring.main.allow-bean-definition-overriding=true
|
||||
@@ -64,7 +64,7 @@ hot.api.url=https://ssl.hot.co.zw/api/v3
|
||||
hot.auth.url=https://ssl.hot.co.zw/api/v3/identity/login
|
||||
hot.access.code=vusumuzi@qantra.co.zw
|
||||
hot.password=Stikbanch@50
|
||||
hot.token.expiry.minutes=25
|
||||
hot.cache.duration.minutes=5
|
||||
|
||||
velocity.api.base-url=https://api.velocityafrica.net
|
||||
velocity.api.api-key=cHE08ADmiATtf8VYgA59-wKVKVKj2WusKDAaaRLDsG8
|
||||
|
||||
@@ -66,4 +66,15 @@
|
||||
<changeSet author="khoza (generated)" id="1780061546055-16">
|
||||
<addUniqueConstraint columnNames="username" constraintName="UC_USERSUSERNAME_COL" tableName="users"/>
|
||||
</changeSet>
|
||||
<changeSet author="khoza (generated)" id="1780062553770-3">
|
||||
<addColumn tableName="provider">
|
||||
<column name="priority" type="integer"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="khoza (generated)" id="1780062553770-1">
|
||||
<dropUniqueConstraint constraintName="UC_USERSUSERNAME_COL" tableName="users"/>
|
||||
</changeSet>
|
||||
<changeSet author="khoza (generated)" id="1780062553770-2">
|
||||
<addUniqueConstraint columnNames="username" constraintName="UC_USERSUSERNAME_COL" tableName="users"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
|
||||
Reference in New Issue
Block a user