bug fixes

This commit is contained in:
2026-06-01 13:27:57 +02:00
parent c2f5b63fa6
commit cc1169f09c
10 changed files with 55 additions and 151 deletions

View File

@@ -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;

View File

@@ -15,4 +15,5 @@ public interface ChargeRepository extends JpaRepository<Charge, UUID> {
List<Charge> 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);
}

View File

@@ -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<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();
@@ -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<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);
return null;
}
}

View File

@@ -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())) {

View File

@@ -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");

View File

@@ -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;

View File

@@ -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.");
}
}
}

View File

@@ -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
velocity.api.cancel-url=https://pay.velocityafrica.net/poll
velocity.api.success-url=https://pay.velocityafrica.net/poll

View File

@@ -1,80 +0,0 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="khoza (generated)" id="1780061546055-17">
<addColumn tableName="transaction">
<column name="order_id" type="varchar(255)"/>
</addColumn>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-18">
<addColumn tableName="transaction">
<column name="order_trace" type="varchar(255)"/>
</addColumn>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-19">
<addColumn tableName="transaction">
<column name="order_transaction_trace" type="varchar(255)"/>
</addColumn>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-20">
<dropColumn columnName="version" tableName="transaction"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-1">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="additional_data"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-2">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="category"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-3">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="charge"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-4">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="charge_condition"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-5">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="currency"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-6">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="integration_processor"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-7">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="otp"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-8">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="payment_processor"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-9">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="provider"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-10">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="recipient"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-11">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="setting"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-12">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="transaction"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-13">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="transaction_event"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-14">
<addDefaultValue columnDataType="boolean" columnName="deleted" defaultValueBoolean="false" tableName="users"/>
</changeSet>
<changeSet author="khoza (generated)" id="1780061546055-15">
<dropUniqueConstraint constraintName="UC_USERSUSERNAME_COL" tableName="users"/>
</changeSet>
<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>

View File

@@ -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