added version control & cloudflare cache clearing
This commit is contained in:
@@ -0,0 +1,57 @@
|
|||||||
|
package zw.qantra.tm.domain.controllers;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import zw.qantra.tm.domain.models.AppVersion;
|
||||||
|
import zw.qantra.tm.domain.services.AppVersionService;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/public/app-version")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppVersionController {
|
||||||
|
|
||||||
|
private final AppVersionService appVersionService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client checks if a newer app build is available.
|
||||||
|
* Pass the current build number as a query param.
|
||||||
|
*/
|
||||||
|
@GetMapping("/check/app")
|
||||||
|
public ResponseEntity<AppVersion> checkAppUpdate(@RequestParam Integer currentBuildNumber) {
|
||||||
|
Optional<AppVersion> update = appVersionService.checkForAppUpdate(currentBuildNumber);
|
||||||
|
return update.map(ResponseEntity::ok)
|
||||||
|
.orElse(ResponseEntity.noContent().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client checks if a newer web build is available.
|
||||||
|
* Pass the current build number as a query param.
|
||||||
|
*/
|
||||||
|
@GetMapping("/check/web")
|
||||||
|
public ResponseEntity<AppVersion> checkWebUpdate(@RequestParam Integer currentBuildNumber) {
|
||||||
|
Optional<AppVersion> update = appVersionService.checkForWebUpdate(currentBuildNumber);
|
||||||
|
return update.map(ResponseEntity::ok)
|
||||||
|
.orElse(ResponseEntity.noContent().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the latest version record.
|
||||||
|
*/
|
||||||
|
@GetMapping("/latest")
|
||||||
|
public ResponseEntity<AppVersion> getLatestVersion() {
|
||||||
|
Optional<AppVersion> latest = appVersionService.getLatestVersion();
|
||||||
|
return latest.map(ResponseEntity::ok)
|
||||||
|
.orElse(ResponseEntity.noContent().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persist a new version record (internal/admin use).
|
||||||
|
*/
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<AppVersion> save(@RequestBody AppVersion appVersion) {
|
||||||
|
return ResponseEntity.ok(appVersionService.save(appVersion));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package zw.qantra.tm.domain.controllers;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import zw.qantra.tm.domain.dtos.CloudflarePurgeResponse;
|
||||||
|
import zw.qantra.tm.domain.services.CloudflareCacheService;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/public/cache/cloudflare")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CloudflareCacheController {
|
||||||
|
|
||||||
|
private final CloudflareCacheService cloudflareCacheService;
|
||||||
|
|
||||||
|
@PostMapping("/clear")
|
||||||
|
public ResponseEntity<CloudflarePurgeResponse> clearCache() {
|
||||||
|
log.info("Received request to clear Cloudflare cache");
|
||||||
|
CloudflarePurgeResponse response = cloudflareCacheService.purgeEverything();
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package zw.qantra.tm.domain.dtos;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CloudflarePurgeResponse {
|
||||||
|
|
||||||
|
private boolean success;
|
||||||
|
private List<CloudflareError> errors;
|
||||||
|
private List<String> messages;
|
||||||
|
private CloudflareResult result;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class CloudflareError {
|
||||||
|
private int code;
|
||||||
|
private String message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class CloudflareResult {
|
||||||
|
private String id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ public class GroupBatchItemUpdateRequest {
|
|||||||
private BigDecimal amount;
|
private BigDecimal amount;
|
||||||
private String recipientName;
|
private String recipientName;
|
||||||
private String recipientPhone;
|
private String recipientPhone;
|
||||||
|
private String recipientAccount;
|
||||||
private String billClientId;
|
private String billClientId;
|
||||||
private String billName;
|
private String billName;
|
||||||
private String billProductName;
|
private String billProductName;
|
||||||
|
|||||||
19
src/main/java/zw/qantra/tm/domain/models/AppVersion.java
Normal file
19
src/main/java/zw/qantra/tm/domain/models/AppVersion.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package zw.qantra.tm.domain.models;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Entity
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class AppVersion extends BaseEntity{
|
||||||
|
private String description;
|
||||||
|
private Integer appBuildNumber;
|
||||||
|
private Integer webBuildNumber;
|
||||||
|
private Timestamp timestamp;
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ public class GroupBatchItem extends BaseEntity {
|
|||||||
private String recipientName;
|
private String recipientName;
|
||||||
@Column(name = "recipient_phone")
|
@Column(name = "recipient_phone")
|
||||||
private String recipientPhone;
|
private String recipientPhone;
|
||||||
|
private String recipientAccount;
|
||||||
private BigDecimal amount;
|
private BigDecimal amount;
|
||||||
|
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package zw.qantra.tm.domain.repositories;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import zw.qantra.tm.domain.models.AppVersion;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface AppVersionRepository extends JpaRepository<AppVersion, UUID> {
|
||||||
|
|
||||||
|
Optional<AppVersion> findTopByOrderByAppBuildNumberDesc();
|
||||||
|
|
||||||
|
Optional<AppVersion> findTopByOrderByWebBuildNumberDesc();
|
||||||
|
|
||||||
|
Optional<AppVersion> findTopByOrderByTimestampDesc();
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package zw.qantra.tm.domain.services;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import zw.qantra.tm.domain.models.AppVersion;
|
||||||
|
import zw.qantra.tm.domain.repositories.AppVersionRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppVersionService {
|
||||||
|
|
||||||
|
private final AppVersionRepository appVersionRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a newer app build number exists than the one provided by the client.
|
||||||
|
*
|
||||||
|
* @param currentBuildNumber the build number the client currently has
|
||||||
|
* @return the latest AppVersion if a newer one exists, empty otherwise
|
||||||
|
*/
|
||||||
|
public Optional<AppVersion> checkForAppUpdate(Integer currentBuildNumber) {
|
||||||
|
Optional<AppVersion> latest = appVersionRepository.findTopByOrderByAppBuildNumberDesc();
|
||||||
|
if (latest.isPresent() && latest.get().getAppBuildNumber() > currentBuildNumber) {
|
||||||
|
return latest;
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a newer web build number exists than the one provided by the client.
|
||||||
|
*
|
||||||
|
* @param currentBuildNumber the build number the client currently has
|
||||||
|
* @return the latest AppVersion if a newer one exists, empty otherwise
|
||||||
|
*/
|
||||||
|
public Optional<AppVersion> checkForWebUpdate(Integer currentBuildNumber) {
|
||||||
|
Optional<AppVersion> latest = appVersionRepository.findTopByOrderByWebBuildNumberDesc();
|
||||||
|
if (latest.isPresent() && latest.get().getWebBuildNumber() > currentBuildNumber) {
|
||||||
|
return latest;
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the latest AppVersion record regardless of build number.
|
||||||
|
*
|
||||||
|
* @return the latest AppVersion by timestamp
|
||||||
|
*/
|
||||||
|
public Optional<AppVersion> getLatestVersion() {
|
||||||
|
return appVersionRepository.findTopByOrderByTimestampDesc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppVersion save(AppVersion appVersion) {
|
||||||
|
return appVersionRepository.save(appVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package zw.qantra.tm.domain.services;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import zw.qantra.tm.domain.dtos.CloudflarePurgeResponse;
|
||||||
|
import zw.qantra.tm.rest.RestService;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CloudflareCacheService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(CloudflareCacheService.class);
|
||||||
|
|
||||||
|
private static final String CLOUDFLARE_API_BASE = "https://api.cloudflare.com/client/v4";
|
||||||
|
|
||||||
|
private final RestService restService;
|
||||||
|
|
||||||
|
@Value("${cloudflare-token}")
|
||||||
|
private String cloudflareToken;
|
||||||
|
|
||||||
|
@Value("${cloudflare-zone-id}")
|
||||||
|
private String cloudflareZoneId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purges the entire Cloudflare cache for the configured zone.
|
||||||
|
*
|
||||||
|
* @return CloudflarePurgeResponse containing success status and any errors
|
||||||
|
*/
|
||||||
|
public CloudflarePurgeResponse purgeEverything() {
|
||||||
|
logger.info("Initiating Cloudflare purge_everything for zone: {}", cloudflareZoneId);
|
||||||
|
|
||||||
|
String path = CLOUDFLARE_API_BASE + "/zones/" + cloudflareZoneId + "/purge_cache";
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setBearerAuth(cloudflareToken);
|
||||||
|
|
||||||
|
Map<String, Boolean> payload = Map.of("purge_everything", true);
|
||||||
|
|
||||||
|
CloudflarePurgeResponse response = restService.postWithExternalAuth(
|
||||||
|
path, payload, headers, CloudflarePurgeResponse.class
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response != null && response.isSuccess()) {
|
||||||
|
logger.info("Cloudflare cache purged successfully for zone: {}", cloudflareZoneId);
|
||||||
|
} else if (response != null) {
|
||||||
|
logger.error("Cloudflare cache purge failed for zone: {}. Errors: {}",
|
||||||
|
cloudflareZoneId, response.getErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,6 +107,7 @@ public class GroupBatchService {
|
|||||||
.recipientId(recipient.getId())
|
.recipientId(recipient.getId())
|
||||||
.recipientName(recipient.getName())
|
.recipientName(recipient.getName())
|
||||||
.recipientPhone(recipient.getPhoneNumber())
|
.recipientPhone(recipient.getPhoneNumber())
|
||||||
|
.recipientAccount(recipient.getAccount())
|
||||||
.amount(defaultAmount)
|
.amount(defaultAmount)
|
||||||
.status(GroupBatchItemStatus.NEW)
|
.status(GroupBatchItemStatus.NEW)
|
||||||
.confirmStatus(GroupBatchItemConfirmStatus.PENDING)
|
.confirmStatus(GroupBatchItemConfirmStatus.PENDING)
|
||||||
@@ -385,6 +386,9 @@ public class GroupBatchService {
|
|||||||
if (update.getRecipientPhone() != null) {
|
if (update.getRecipientPhone() != null) {
|
||||||
item.setRecipientPhone(update.getRecipientPhone());
|
item.setRecipientPhone(update.getRecipientPhone());
|
||||||
}
|
}
|
||||||
|
if (update.getRecipientAccount() != null) {
|
||||||
|
item.setRecipientAccount(update.getRecipientAccount());
|
||||||
|
}
|
||||||
if (update.getBillClientId() != null) {
|
if (update.getBillClientId() != null) {
|
||||||
item.setBillClientId(update.getBillClientId());
|
item.setBillClientId(update.getBillClientId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.springframework.cache.annotation.Cacheable;
|
|||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import zw.qantra.tm.rest.RestService;
|
import zw.qantra.tm.rest.RestService;
|
||||||
|
import zw.qantra.tm.utils.Utils;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -21,6 +22,7 @@ public class HotRechargeBalanceService {
|
|||||||
Logger logger = LoggerFactory.getLogger(HotRechargeBalanceService.class);
|
Logger logger = LoggerFactory.getLogger(HotRechargeBalanceService.class);
|
||||||
|
|
||||||
private final RestService restService;
|
private final RestService restService;
|
||||||
|
private final SettingService settingService;
|
||||||
|
|
||||||
@Value("${hot.api.url:https://ssl.hot.co.zw/api/v3}")
|
@Value("${hot.api.url:https://ssl.hot.co.zw/api/v3}")
|
||||||
private String hotApiUrl;
|
private String hotApiUrl;
|
||||||
@@ -28,6 +30,10 @@ public class HotRechargeBalanceService {
|
|||||||
@Cacheable(value = "hotrechargeBalance", key = "#token + '_' + #amount.toString()")
|
@Cacheable(value = "hotrechargeBalance", key = "#token + '_' + #amount.toString()")
|
||||||
public boolean checkBalance(String token, BigDecimal amount, String accId) {
|
public boolean checkBalance(String token, BigDecimal amount, String accId) {
|
||||||
try {
|
try {
|
||||||
|
if(settingService.getBooleanSetting("SIMULATE_HOT_SUCCESS")){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
String balanceUrl = hotApiUrl + "/account/balance/" + accId;
|
String balanceUrl = hotApiUrl + "/account/balance/" + accId;
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setBearerAuth(token);
|
headers.setBearerAuth(token);
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ public class RecipientGroupService {
|
|||||||
.recipientId(recipient.getId())
|
.recipientId(recipient.getId())
|
||||||
.recipientName(recipient.getName())
|
.recipientName(recipient.getName())
|
||||||
.recipientPhone(recipient.getPhoneNumber())
|
.recipientPhone(recipient.getPhoneNumber())
|
||||||
|
.recipientAccount(recipient.getAccount())
|
||||||
.status(GroupBatchItemStatus.NEW)
|
.status(GroupBatchItemStatus.NEW)
|
||||||
.confirmStatus(GroupBatchItemConfirmStatus.PENDING)
|
.confirmStatus(GroupBatchItemConfirmStatus.PENDING)
|
||||||
.integrationStatus(GroupBatchItemIntegrationStatus.PENDING)
|
.integrationStatus(GroupBatchItemIntegrationStatus.PENDING)
|
||||||
@@ -217,6 +218,7 @@ public class RecipientGroupService {
|
|||||||
try {
|
try {
|
||||||
item.setRecipientName(update.row.name);
|
item.setRecipientName(update.row.name);
|
||||||
item.setRecipientPhone(update.row.phone);
|
item.setRecipientPhone(update.row.phone);
|
||||||
|
item.setRecipientAccount(update.row.account);
|
||||||
item.setBillName(update.provider.getName());
|
item.setBillName(update.provider.getName());
|
||||||
item.setBillProductName(update.row.billProductName);
|
item.setBillProductName(update.row.billProductName);
|
||||||
item.setProviderLabel(update.row.billLabel);
|
item.setProviderLabel(update.row.billLabel);
|
||||||
@@ -474,7 +476,10 @@ public class RecipientGroupService {
|
|||||||
|
|
||||||
List<Recipient> existing = recipientRepository.findByAccountAndUserId(incomingRecipient.getAccount(), recipientUserId);
|
List<Recipient> existing = recipientRepository.findByAccountAndUserId(incomingRecipient.getAccount(), recipientUserId);
|
||||||
if (!existing.isEmpty()) {
|
if (!existing.isEmpty()) {
|
||||||
return existing.get(0);
|
Recipient recipient = existing.get(0);
|
||||||
|
recipient.setName(incomingRecipient.getName());
|
||||||
|
recipient.setPhoneNumber(incomingRecipient.getPhoneNumber());
|
||||||
|
return recipientRepository.save(recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
incomingRecipient.setId(null);
|
incomingRecipient.setId(null);
|
||||||
|
|||||||
@@ -39,27 +39,14 @@ public class ZesaConfirmationHotProcessor implements TransactionProcessorInterfa
|
|||||||
@Value("${hot.api.url:https://ssl.hot.co.zw/api/v3}")
|
@Value("${hot.api.url:https://ssl.hot.co.zw/api/v3}")
|
||||||
private String hotApiUrl;
|
private String hotApiUrl;
|
||||||
|
|
||||||
|
String token;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object process(Transaction transaction) throws Exception {
|
public Object process(Transaction transaction) throws Exception {
|
||||||
logger.info("Processing ZESA confirmation from HotRecharge");
|
logger.info("Processing ZESA confirmation from HotRecharge");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// do this if we not simulating success, if simulating success, we skip balance check and just return success
|
Map<String, Object> customerData = checkCustomer(transaction);
|
||||||
if(settingService.getBooleanSetting("SIMULATE_HOT_SUCCESS")){
|
|
||||||
transaction.setStatus(Status.SUCCESS);
|
|
||||||
transaction.setResponseCode("02");
|
|
||||||
return transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
String token = hotRechargeTokenService.getToken();
|
|
||||||
if (token == null || token.isEmpty()) {
|
|
||||||
transaction.setStatus(Status.FAILED);
|
|
||||||
transaction.setResponseCode("91");
|
|
||||||
transaction.setErrorMessage("Failed to authenticate with HotRecharge");
|
|
||||||
return transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> customerData = checkCustomer(token, transaction);
|
|
||||||
if (customerData == null) {
|
if (customerData == null) {
|
||||||
transaction.setStatus(Status.FAILED);
|
transaction.setStatus(Status.FAILED);
|
||||||
transaction.setResponseCode("90");
|
transaction.setResponseCode("90");
|
||||||
@@ -84,6 +71,7 @@ public class ZesaConfirmationHotProcessor implements TransactionProcessorInterfa
|
|||||||
|
|
||||||
transaction.setCreditAmount(transactionService.calculateCreditAmount(transaction));
|
transaction.setCreditAmount(transactionService.calculateCreditAmount(transaction));
|
||||||
|
|
||||||
|
// token should've been updated by checkCustomer
|
||||||
if (!hotRechargeBalanceService.checkBalance(token, transaction.getCreditAmount(), accId)) {
|
if (!hotRechargeBalanceService.checkBalance(token, transaction.getCreditAmount(), accId)) {
|
||||||
transaction.setStatus(Status.FAILED);
|
transaction.setStatus(Status.FAILED);
|
||||||
transaction.setResponseCode("92");
|
transaction.setResponseCode("92");
|
||||||
@@ -161,7 +149,25 @@ public class ZesaConfirmationHotProcessor implements TransactionProcessorInterfa
|
|||||||
return currency == null ? "" : currency.toString().trim();
|
return currency == null ? "" : currency.toString().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> checkCustomer(String token, Transaction transaction) {
|
private Map<String, Object> checkCustomer(Transaction transaction) {
|
||||||
|
if(settingService.getBooleanSetting("SIMULATE_HOT_SUCCESS")){
|
||||||
|
logger.info("Simulating HotRecharge success");
|
||||||
|
return Utils.fromJson("{\n" +
|
||||||
|
" \"accountNumber\": \"07088597534\",\n" +
|
||||||
|
" \"details\": {\n" +
|
||||||
|
" \"AccountName\": \"CHIRINDO LETWINA\\n2144 MARLBOROUGH\",\n" +
|
||||||
|
" \"Status\": \"Active\",\n" +
|
||||||
|
" \"Currency\": \"ZWG\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}", LinkedHashMap.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
token = hotRechargeTokenService.getToken();
|
||||||
|
if (token == null || token.isEmpty()) {
|
||||||
|
throw new ApiException("Failed to authenticate with HotRecharge");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String hotProductId = providerService.getProviderId(transaction.getBillClientId());
|
String hotProductId = providerService.getProviderId(transaction.getBillClientId());
|
||||||
|
|
||||||
|
|||||||
@@ -55,29 +55,12 @@ public class HotRechargeIntegrationProcessor implements TransactionProcessorInte
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(settingService.getBooleanSetting("SIMULATE_HOT_SUCCESS")){
|
|
||||||
transaction.setStatus(Status.SUCCESS);
|
|
||||||
transaction.setResponseCode("02");
|
|
||||||
transaction.setCreditRef("Simulated Integration Success");
|
|
||||||
transaction.setErrorMessage(null);
|
|
||||||
return transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.info("Processing HotRecharge integration");
|
logger.info("Processing HotRecharge integration");
|
||||||
String token = hotRechargeTokenService.getToken();
|
|
||||||
|
|
||||||
if (token == null || token.isEmpty()) {
|
|
||||||
transaction.setStatus(Status.FAILED);
|
|
||||||
transaction.setResponseCode("91");
|
|
||||||
transaction.setErrorMessage("Failed to authenticate with HotRecharge");
|
|
||||||
return transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: a balance check might be necessary here. Removing
|
// todo: a balance check might be necessary here. Removing
|
||||||
// for now so not to spam hotrecharge with requests
|
// for now so not to spam hotrecharge with requests
|
||||||
|
|
||||||
LinkedHashMap<String, Object> rechargeResponse = performRecharge(token, transaction);
|
LinkedHashMap<String, Object> rechargeResponse = performRecharge(transaction);
|
||||||
if (rechargeResponse == null) {
|
if (rechargeResponse == null) {
|
||||||
transaction.setStatus(Status.FAILED);
|
transaction.setStatus(Status.FAILED);
|
||||||
transaction.setResponseCode("99");
|
transaction.setResponseCode("99");
|
||||||
@@ -137,8 +120,40 @@ public class HotRechargeIntegrationProcessor implements TransactionProcessorInte
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkedHashMap<String, Object> performRecharge(String token, Transaction transaction) {
|
private LinkedHashMap<String, Object> performRecharge(Transaction transaction) {
|
||||||
|
if(settingService.getBooleanSetting("SIMULATE_HOT_SUCCESS")){
|
||||||
|
logger.info("Simulating HotRecharge success");
|
||||||
|
return Utils.fromJson("{\n" +
|
||||||
|
" \"successful\": true,\n" +
|
||||||
|
" \"rechargeId\": 1.9080854E8,\n" +
|
||||||
|
" \"amount\": 265.0,\n" +
|
||||||
|
" \"discount\": 1.2,\n" +
|
||||||
|
" \"balance\": {\n" +
|
||||||
|
" \"accountTypeId\": 2.0,\n" +
|
||||||
|
" \"name\": \"Utility ZWG\",\n" +
|
||||||
|
" \"balance\": 3306.32\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"message\": \"Transaction processed successfully\",\n" +
|
||||||
|
" \"rechargeData\": {\n" +
|
||||||
|
" \"Network\": \"ZESA\",\n" +
|
||||||
|
" \"Target\": \"07088597534\",\n" +
|
||||||
|
" \"Cost\": \"261.8200\",\n" +
|
||||||
|
" \"Token\": \"6616 0517 2063 6675 8254\",\n" +
|
||||||
|
" \"Units\": \"40.92\",\n" +
|
||||||
|
" \"NetAmount\": \"250\",\n" +
|
||||||
|
" \"TaxAmount\": \"0\",\n" +
|
||||||
|
" \"Levy\": \"15\",\n" +
|
||||||
|
" \"Arrears\": \"0\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}", LinkedHashMap.class);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
String token = hotRechargeTokenService.getToken();
|
||||||
|
|
||||||
|
if (token == null || token.isEmpty()) {
|
||||||
|
throw new Exception("Failed to authenticate with HotRecharge");
|
||||||
|
}
|
||||||
String rechargeUrl = hotApiUrl + "/products/recharge";
|
String rechargeUrl = hotApiUrl + "/products/recharge";
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setBearerAuth(token);
|
headers.setBearerAuth(token);
|
||||||
|
|||||||
@@ -87,3 +87,6 @@ app.base-url=https://pay.velocityafrica.net
|
|||||||
zss.sms.api.url=https://secure.zss.co.zw/vportal/cnm/vsms/json/batch
|
zss.sms.api.url=https://secure.zss.co.zw/vportal/cnm/vsms/json/batch
|
||||||
zss.sms.api.auth=Basic UWFudHJhdGVjaDpVbUk3OUpwUDh3QTY=
|
zss.sms.api.auth=Basic UWFudHJhdGVjaDpVbUk3OUpwUDh3QTY=
|
||||||
sms.debug=false
|
sms.debug=false
|
||||||
|
|
||||||
|
cloudflare-token=cfut_U0qhvhzAATLqHQa9lad7oRmBmPoJ6n9uIoCBbNOWc9884f18
|
||||||
|
cloudflare-zone-id=378cea8e50c0d9a158816109b3b1fd8d
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
<?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">
|
<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="1781914969011-3">
|
<changeSet author="khoza (generated)" id="1781993557092-7">
|
||||||
<addColumn tableName="transaction">
|
<addColumn tableName="group_batch_item">
|
||||||
<column name="credit_address" type="varchar(255)"/>
|
<column name="recipient_account" type="varchar(255)"/>
|
||||||
</addColumn>
|
|
||||||
</changeSet>
|
|
||||||
<changeSet author="khoza (generated)" id="1781914969011-4">
|
|
||||||
<addColumn tableName="transaction">
|
|
||||||
<column name="credit_voucher" type="varchar(255)"/>
|
|
||||||
</addColumn>
|
</addColumn>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
Reference in New Issue
Block a user