diff --git a/src/main/java/zw/qantra/tm/domain/models/Transaction.java b/src/main/java/zw/qantra/tm/domain/models/Transaction.java index fa08359..a83b4e1 100644 --- a/src/main/java/zw/qantra/tm/domain/models/Transaction.java +++ b/src/main/java/zw/qantra/tm/domain/models/Transaction.java @@ -23,6 +23,7 @@ import java.util.UUID; public class Transaction extends BaseEntity { private String userId; private String trace; + private String region; private BigDecimal amount; private BigDecimal charge; private BigDecimal gatewayCharge; diff --git a/src/main/java/zw/qantra/tm/domain/repositories/ChargeRepository.java b/src/main/java/zw/qantra/tm/domain/repositories/ChargeRepository.java index b00b120..f6c7918 100644 --- a/src/main/java/zw/qantra/tm/domain/repositories/ChargeRepository.java +++ b/src/main/java/zw/qantra/tm/domain/repositories/ChargeRepository.java @@ -15,4 +15,5 @@ public interface ChargeRepository extends JpaRepository { List findAllByCurrency(CurrencyType currency); boolean existsByChargeLabelAndCurrency(ChargeLabelEnum chargeLabel, CurrencyType currency); boolean existsByChargeLabelAndCurrencyAndPercentageRate(ChargeLabelEnum chargeLabel, CurrencyType currency, BigDecimal percentageRate); + boolean existsByChargeLabelAndCurrencyAndDescription(ChargeLabelEnum chargeLabel, CurrencyType currency, String description); } \ No newline at end of file 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 0ed309c..a92264f 100644 --- a/src/main/java/zw/qantra/tm/domain/services/HotRechargeTokenService.java +++ b/src/main/java/zw/qantra/tm/domain/services/HotRechargeTokenService.java @@ -34,52 +34,6 @@ public class HotRechargeTokenService { private long cacheExpiryTime; public synchronized String getToken() { - if (isCacheValid()) { - logger.info("Cache is valid, attempting token refresh"); - return refreshCachedToken(); - } - return fetchNewToken(); - } - - private boolean isCacheValid() { - return cachedToken != null && cachedRefreshToken != null && System.currentTimeMillis() < cacheExpiryTime; - } - - private synchronized String refreshCachedToken() { - if (!isCacheValid()) { - return fetchNewToken(); - } - - try { - 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(); @@ -99,9 +53,33 @@ public class HotRechargeTokenService { 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; + logger.error("Failed to fetch HotRecharge token: {}", e.getMessage(), e); + logger.info("Trying to refresh token"); + return refreshCachedToken(); + } + } + + private synchronized String refreshCachedToken() { + try { + 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); return null; } } 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 1a71ab0..db6ab7c 100644 --- a/src/main/java/zw/qantra/tm/domain/services/VelocityPaymentService.java +++ b/src/main/java/zw/qantra/tm/domain/services/VelocityPaymentService.java @@ -155,10 +155,10 @@ public class VelocityPaymentService { .paymentProcessorLabel(paymentProcessorLabel) .debitCurrency(transaction.getDebitCurrency().name()) .debitRef(transaction.getErpSalesRef()) - .creditPhone(velocityApiProperties.getCreditPhone()) + .creditPhone("") .creditRegion("ZW") - .creditAccount(velocityApiProperties.getCreditAccount()) - .authType(velocityApiProperties.getDefaultAuthType()) + .creditAccount("") + .authType(paymentProcessorLabel.equals("VMC") ? "WEB" : "REMOTE") .build(); if ("MPGS".equalsIgnoreCase(transaction.getPaymentProcessorLabel())) { 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 9299f7f..4d1ffed 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 @@ -59,9 +59,15 @@ public class NetoneConfirmationHotProcessor implements TransactionProcessorInter put("value", transaction.getBillName()); }}); additionalDataList.add(new HashMap() {{ - put("name", "Destination Phone Number"); + put("name", "From"); + put("value", transaction.getDebitPhone()); + }}); + + additionalDataList.add(new HashMap() {{ + put("name", "To"); put("value", transaction.getCreditAccount()); }}); + if(transaction.getBillProductName() != null && !transaction.getBillProductName().isEmpty()) { additionalDataList.add(new HashMap() {{ put("name", "Product"); 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 9cf6d31..8c57556 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 @@ -74,14 +74,12 @@ public class CleanupHandler implements HandlerInterface { String debitPhoneNumber = transaction.getDebitPhone(); String creditPhoneNumber = transaction.getCreditPhone(); - PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); - if(debitPhoneNumber != null && !debitPhoneNumber.isEmpty()){ - transaction.setDebitPhone(Utils.formatPhoneNumber(debitPhoneNumber, "")); + transaction.setDebitPhone(Utils.formatPhoneNumber(debitPhoneNumber, transaction.getRegion())); } if(creditPhoneNumber != null && !creditPhoneNumber.isEmpty()){ - transaction.setDebitPhone(Utils.formatPhoneNumber(creditPhoneNumber, "ZW")); + transaction.setCreditAccount(Utils.formatPhoneNumber(creditPhoneNumber, "ZW")); } return transaction; diff --git a/src/main/java/zw/qantra/tm/seeders/ChargeSeeder.java b/src/main/java/zw/qantra/tm/seeders/ChargeSeeder.java index 7e7fa61..f84b9d7 100644 --- a/src/main/java/zw/qantra/tm/seeders/ChargeSeeder.java +++ b/src/main/java/zw/qantra/tm/seeders/ChargeSeeder.java @@ -39,34 +39,34 @@ public class ChargeSeeder implements Seeder { } // Ecocash Gateway Fee (1%) - if (chargeRepository.existsByChargeLabelAndCurrencyAndPercentageRate( - ChargeLabelEnum.GATEWAY_FEE, CurrencyType.USD, new BigDecimal("1"))) { - log.info("Charge 'Gateway fee (1%)' already exists, skipping."); + if (chargeRepository.existsByChargeLabelAndCurrencyAndDescription( + ChargeLabelEnum.GATEWAY_FEE, CurrencyType.USD, "Ecocash Gateway fee")) { + log.info("Charge 'Ecocash Gateway fee (1%)' already exists, skipping."); } else { chargeRepository.save(Charge.builder() - .description("Gateway fee") + .description("Ecocash Gateway fee") .chargeLabel(ChargeLabelEnum.GATEWAY_FEE) .currency(CurrencyType.USD) .percentageRate(new BigDecimal("1")) .includes(new HashSet<>(Arrays.asList(ecocashCondition))) .build()); - log.info("Charge 'Gateway fee (1%)' seeded."); + log.info("Charge 'Ecocash Gateway fee (1%)' seeded."); } // MPGS Gateway Fee (2%, min 0.55) - if (chargeRepository.existsByChargeLabelAndCurrencyAndPercentageRate( - ChargeLabelEnum.GATEWAY_FEE, CurrencyType.USD, new BigDecimal("2"))) { - log.info("Charge 'Gateway fee (2%)' already exists, skipping."); + if (chargeRepository.existsByChargeLabelAndCurrencyAndDescription( + ChargeLabelEnum.GATEWAY_FEE, CurrencyType.USD, "MPGS Gateway fee")) { + log.info("Charge 'MPGS Gateway fee (1% min 0.50)' already exists, skipping."); } else { chargeRepository.save(Charge.builder() - .description("Gateway fee") + .description("MPGS Gateway fee") .chargeLabel(ChargeLabelEnum.GATEWAY_FEE) .currency(CurrencyType.USD) .percentageRate(new BigDecimal("1")) - .min(new BigDecimal("0.20")) + .min(new BigDecimal("0.50")) .includes(new HashSet<>(Arrays.asList(mpgsCondition))) .build()); - log.info("Charge 'Gateway fee (2%)' seeded."); + log.info("Charge 'MPGS Gateway fee (1% min 0.50)' seeded."); } } } \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0c79081..ec80b0e 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -68,5 +68,5 @@ hot.cache.duration.minutes=5 velocity.api.base-url=https://api.velocityafrica.net velocity.api.api-key=cHE08ADmiATtf8VYgA59-wKVKVKj2WusKDAaaRLDsG8 -velocity.api.cancel-url=https://pay.velocityafrica/poll -velocity.api.success-url=https://pay.velocityafrica/poll \ No newline at end of file +velocity.api.cancel-url=https://pay.velocityafrica.net/poll +velocity.api.success-url=https://pay.velocityafrica.net/poll \ No newline at end of file diff --git a/src/main/resources/liquibase-diff-changeLog.xml b/src/main/resources/liquibase-diff-changeLog.xml deleted file mode 100644 index 68040b4..0000000 --- a/src/main/resources/liquibase-diff-changeLog.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/liquibase-lab.properties b/src/main/resources/liquibase-lab.properties index f4128ab..7661774 100644 --- a/src/main/resources/liquibase-lab.properties +++ b/src/main/resources/liquibase-lab.properties @@ -1,7 +1,7 @@ changeLogFile=src/main/resources/liquibase-diff-changeLog.xml url=jdbc:postgresql://localhost:5432/qpay?serverTimezone=Africa/Harare&useLegacyDatetimeCode=false username=postgres -password=zdDZMzq6F4B4L1IUl +password=example driver=org.postgresql.Driver referenceUrl=hibernate:spring:zw.qantra.tm.domain.models?dialect=org.hibernate.dialect.PostgreSQLDialect&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy&hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy