diff --git a/src/main/java/zw/qantra/tm/domain/controllers/ProviderController.java b/src/main/java/zw/qantra/tm/domain/controllers/ProviderController.java index 1f6d8ce..42f2bb0 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/ProviderController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/ProviderController.java @@ -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 spec, Pageable pageable) { + return ResponseEntity.ok(providerService.findAll(spec, pageable)); } @GetMapping("/{id}/products") diff --git a/src/main/java/zw/qantra/tm/domain/models/Provider.java b/src/main/java/zw/qantra/tm/domain/models/Provider.java index 1fa4c2b..b7f07bd 100644 --- a/src/main/java/zw/qantra/tm/domain/models/Provider.java +++ b/src/main/java/zw/qantra/tm/domain/models/Provider.java @@ -30,4 +30,5 @@ public class Provider extends BaseEntity { private double percentageCommission; @Column(columnDefinition = "TEXT") private String meta; + private Integer priority; } diff --git a/src/main/java/zw/qantra/tm/domain/repositories/ProviderRepository.java b/src/main/java/zw/qantra/tm/domain/repositories/ProviderRepository.java index 6f23b27..b69b3dd 100644 --- a/src/main/java/zw/qantra/tm/domain/repositories/ProviderRepository.java +++ b/src/main/java/zw/qantra/tm/domain/repositories/ProviderRepository.java @@ -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 { +public interface ProviderRepository extends JpaRepository, JpaSpecificationExecutor { List findByCategory(String category); Provider findByClientId(String clientId); boolean existsByClientId(String clientId); diff --git a/src/main/java/zw/qantra/tm/domain/services/HotRechargeTokenService.java b/src/main/java/zw/qantra/tm/domain/services/HotRechargeTokenService.java index 44362a3..0ed309c 100644 --- a/src/main/java/zw/qantra/tm/domain/services/HotRechargeTokenService.java +++ b/src/main/java/zw/qantra/tm/domain/services/HotRechargeTokenService.java @@ -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 payload = Map.of( + "token", cachedToken, + "refreshToken", cachedRefreshToken + ); + + LinkedHashMap 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 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; } -} - +} \ No newline at end of file diff --git a/src/main/java/zw/qantra/tm/domain/services/ProviderService.java b/src/main/java/zw/qantra/tm/domain/services/ProviderService.java index 4833dd5..0224aa1 100644 --- a/src/main/java/zw/qantra/tm/domain/services/ProviderService.java +++ b/src/main/java/zw/qantra/tm/domain/services/ProviderService.java @@ -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 existingProviders; - if (category != null && !category.isEmpty()) { - existingProviders = getProviderRepository().findByCategory(category); - } else { - existingProviders = getProviderRepository().findAll(); - } - - return existingProviders; + public Object findAll(Specification specification, Pageable pageable) { + return getProviderRepository().findAll(specification, pageable); } public Object getProviders(List existingProviders) { diff --git a/src/main/java/zw/qantra/tm/domain/services/VelocityPaymentService.java b/src/main/java/zw/qantra/tm/domain/services/VelocityPaymentService.java index c8ae07c..1a71ab0 100644 --- a/src/main/java/zw/qantra/tm/domain/services/VelocityPaymentService.java +++ b/src/main/java/zw/qantra/tm/domain/services/VelocityPaymentService.java @@ -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); diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/EconetBundlesConfirmationHotProcessor.java b/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/EconetBundlesConfirmationHotProcessor.java index 873e9ec..d5bc647 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/EconetBundlesConfirmationHotProcessor.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/EconetBundlesConfirmationHotProcessor.java @@ -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); } } \ No newline at end of file diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/EconetConfirmationHotProcessor.java b/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/EconetConfirmationHotProcessor.java index 985101f..fbc7ab3 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/EconetConfirmationHotProcessor.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/EconetConfirmationHotProcessor.java @@ -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); } } \ No newline at end of file diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/NetoneConfirmationHotProcessor.java b/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/NetoneConfirmationHotProcessor.java index 7990761..9299f7f 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/NetoneConfirmationHotProcessor.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/NetoneConfirmationHotProcessor.java @@ -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"); diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/ZesaConfirmationHotProcessor.java b/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/ZesaConfirmationHotProcessor.java index 3eb5197..8486344 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/ZesaConfirmationHotProcessor.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/confirmations/hotrecharge/ZesaConfirmationHotProcessor.java @@ -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); diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/handlers/LogicHandler.java b/src/main/java/zw/qantra/tm/domain/services/processors/handlers/LogicHandler.java deleted file mode 100644 index c10f029..0000000 --- a/src/main/java/zw/qantra/tm/domain/services/processors/handlers/LogicHandler.java +++ /dev/null @@ -1,5 +0,0 @@ -package zw.qantra.tm.domain.services.processors.handlers; - -public interface LogicHandler { - O process(I input); -} diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/handlers/LogicPipeline.java b/src/main/java/zw/qantra/tm/domain/services/processors/handlers/LogicPipeline.java deleted file mode 100644 index 8262d19..0000000 --- a/src/main/java/zw/qantra/tm/domain/services/processors/handlers/LogicPipeline.java +++ /dev/null @@ -1,18 +0,0 @@ -package zw.qantra.tm.domain.services.processors.handlers; - -public class LogicPipeline { - - private final LogicHandler currentHandler; - - public LogicPipeline(LogicHandler currentHandler) { - this.currentHandler = currentHandler; - } - - public LogicPipeline addHandler(LogicHandler newHandler) { - return new LogicPipeline<>(input -> newHandler.process(currentHandler.process(input))); - } - - public O execute(I input) { - return currentHandler.process(input); - } -} \ No newline at end of file diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/payments/EcocashRemotePaymentProcessor.java b/src/main/java/zw/qantra/tm/domain/services/processors/payments/EcocashRemotePaymentProcessor.java index dd60ec8..1febe40 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/payments/EcocashRemotePaymentProcessor.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/payments/EcocashRemotePaymentProcessor.java @@ -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; diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/workflows/RegistrationWorkflow.java b/src/main/java/zw/qantra/tm/domain/services/processors/workflows/RegistrationWorkflow.java index 7793574..df0a4a5 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/workflows/RegistrationWorkflow.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/workflows/RegistrationWorkflow.java @@ -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); diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/workflows/handlers/CleanupHandler.java b/src/main/java/zw/qantra/tm/domain/services/processors/workflows/handlers/CleanupHandler.java index 5920826..9cf6d31 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/workflows/handlers/CleanupHandler.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/workflows/handlers/CleanupHandler.java @@ -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; diff --git a/src/main/java/zw/qantra/tm/domain/services/processors/workflows/handlers/RecipientsUpdateHandler.java b/src/main/java/zw/qantra/tm/domain/services/processors/workflows/handlers/RecipientsUpdateHandler.java index cbbad77..2f2fdba 100644 --- a/src/main/java/zw/qantra/tm/domain/services/processors/workflows/handlers/RecipientsUpdateHandler.java +++ b/src/main/java/zw/qantra/tm/domain/services/processors/workflows/handlers/RecipientsUpdateHandler.java @@ -24,7 +24,7 @@ public class RecipientsUpdateHandler implements HandlerInterface { List 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(); diff --git a/src/main/java/zw/qantra/tm/rest/RestTemplateInterceptor.java b/src/main/java/zw/qantra/tm/rest/RestTemplateInterceptor.java deleted file mode 100755 index 07597dd..0000000 --- a/src/main/java/zw/qantra/tm/rest/RestTemplateInterceptor.java +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/src/main/java/zw/qantra/tm/seeders/ProviderSeeder.java b/src/main/java/zw/qantra/tm/seeders/ProviderSeeder.java index d36b63e..87bb352 100644 --- a/src/main/java/zw/qantra/tm/seeders/ProviderSeeder.java +++ b/src/main/java/zw/qantra/tm/seeders/ProviderSeeder.java @@ -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() ); diff --git a/src/main/java/zw/qantra/tm/utils/Utils.java b/src/main/java/zw/qantra/tm/utils/Utils.java index e3d96dc..07ba871 100644 --- a/src/main/java/zw/qantra/tm/utils/Utils.java +++ b/src/main/java/zw/qantra/tm/utils/Utils.java @@ -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 deepCopy(Object object, Class clazz) { String json = toJson(object); return fromJson(json, clazz); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d745375..0c79081 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -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 diff --git a/src/main/resources/liquibase-diff-changeLog.xml b/src/main/resources/liquibase-diff-changeLog.xml index 4f32cd5..68040b4 100644 --- a/src/main/resources/liquibase-diff-changeLog.xml +++ b/src/main/resources/liquibase-diff-changeLog.xml @@ -66,4 +66,15 @@ + + + + + + + + + + +