adding citywallet support
This commit is contained in:
Binary file not shown.
64
data/jobrunr.trace.db
Normal file
64
data/jobrunr.trace.db
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
2026-06-11 11:30:43.191867+02:00 database: flush
|
||||||
|
org.h2.message.DbException: General error: "org.h2.mvstore.MVStoreException: The file is locked: /Users/khoza/dev/qantra/qpay-transaction-manager-spring-boot/data/jobrunr.mv.db [2.2.224/7]" [50000-224]
|
||||||
|
at org.h2.message.DbException.get(DbException.java:212)
|
||||||
|
at org.h2.message.DbException.convert(DbException.java:407)
|
||||||
|
at org.h2.mvstore.db.Store.lambda$new$0(Store.java:122)
|
||||||
|
at org.h2.mvstore.MVStore.handleException(MVStore.java:1546)
|
||||||
|
at org.h2.mvstore.MVStore.panic(MVStore.java:371)
|
||||||
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:291)
|
||||||
|
at org.h2.mvstore.MVStore$Builder.open(MVStore.java:2035)
|
||||||
|
at org.h2.mvstore.db.Store.<init>(Store.java:133)
|
||||||
|
at org.h2.engine.Database.<init>(Database.java:326)
|
||||||
|
at org.h2.engine.Engine.openSession(Engine.java:92)
|
||||||
|
at org.h2.engine.Engine.openSession(Engine.java:222)
|
||||||
|
at org.h2.engine.Engine.createSession(Engine.java:201)
|
||||||
|
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:343)
|
||||||
|
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:125)
|
||||||
|
at org.h2.Driver.connect(Driver.java:59)
|
||||||
|
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:137)
|
||||||
|
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:360)
|
||||||
|
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:202)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:461)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:550)
|
||||||
|
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:98)
|
||||||
|
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:111)
|
||||||
|
at org.jobrunr.storage.sql.common.SqlStorageProviderFactory.getStorageProviderUsingDataSource(SqlStorageProviderFactory.java:40)
|
||||||
|
at org.jobrunr.storage.sql.common.SqlStorageProviderFactory.using(SqlStorageProviderFactory.java:36)
|
||||||
|
at org.jobrunr.storage.sql.common.SqlStorageProviderFactory.using(SqlStorageProviderFactory.java:31)
|
||||||
|
at org.jobrunr.spring.autoconfigure.storage.JobRunrSqlStorageAutoConfiguration.sqlStorageProvider(JobRunrSqlStorageAutoConfiguration.java:33)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||||
|
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
|
||||||
|
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
|
||||||
|
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:146)
|
||||||
|
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:644)
|
||||||
|
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
|
||||||
|
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
|
||||||
|
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
|
||||||
|
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
|
||||||
|
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971)
|
||||||
|
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
|
||||||
|
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
|
||||||
|
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
|
||||||
|
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
|
||||||
|
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
|
||||||
|
at zw.qantra.tm.TmApplication.main(TmApplication.java:20)
|
||||||
|
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: /Users/khoza/dev/qantra/qpay-transaction-manager-spring-boot/data/jobrunr.mv.db [2.2.224/7]" [50000-224]
|
||||||
|
at org.h2.message.DbException.getJdbcSQLException(DbException.java:566)
|
||||||
|
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
|
||||||
|
... 51 more
|
||||||
|
Caused by: org.h2.mvstore.MVStoreException: The file is locked: /Users/khoza/dev/qantra/qpay-transaction-manager-spring-boot/data/jobrunr.mv.db [2.2.224/7]
|
||||||
|
at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:996)
|
||||||
|
at org.h2.mvstore.SingleFileStore.lockFileChannel(SingleFileStore.java:143)
|
||||||
|
at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:117)
|
||||||
|
at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:81)
|
||||||
|
at org.h2.mvstore.MVStore.<init>(MVStore.java:286)
|
||||||
|
... 45 more
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package zw.qantra.tm.domain.controllers;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import zw.qantra.tm.domain.dtos.erp.VelocityAccountDto;
|
||||||
|
import zw.qantra.tm.domain.dtos.erp.VelocityStatementDto;
|
||||||
|
import zw.qantra.tm.domain.services.VelocityAccountService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/accounts")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AccountController {
|
||||||
|
|
||||||
|
private final VelocityAccountService velocityAccountService;
|
||||||
|
private static final List<String> SUPPORTED_CURRENCIES = List.of("USD", "ZWG");
|
||||||
|
|
||||||
|
@GetMapping("/phone/{currencyPhoneConcat}")
|
||||||
|
@PreAuthorize("hasRole('ACCOUNT_READ')")
|
||||||
|
public ResponseEntity<VelocityAccountDto> getAccountByPhone(
|
||||||
|
@PathVariable String currencyPhoneConcat) {
|
||||||
|
try {
|
||||||
|
VelocityAccountDto account = velocityAccountService.getAccountByPhone(currencyPhoneConcat);
|
||||||
|
return ResponseEntity.ok(account);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.badRequest().build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/phone/{currencyPhoneConcat}/statement")
|
||||||
|
@PreAuthorize("hasRole('ACCOUNT_READ')")
|
||||||
|
public ResponseEntity<VelocityStatementDto> getStatementByPhone(
|
||||||
|
@PathVariable String currencyPhoneConcat,
|
||||||
|
@RequestParam String startDate,
|
||||||
|
@RequestParam String endDate) {
|
||||||
|
try {
|
||||||
|
VelocityStatementDto statement = velocityAccountService.getStatementByPhone(
|
||||||
|
currencyPhoneConcat, startDate, endDate);
|
||||||
|
return ResponseEntity.ok(statement);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.badRequest().build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import zw.qantra.tm.domain.services.processors.payments.CityWalletRemotePaymentProcessor;
|
||||||
import zw.qantra.tm.domain.services.processors.workflows.TransactionWorkflow;
|
import zw.qantra.tm.domain.services.processors.workflows.TransactionWorkflow;
|
||||||
import zw.qantra.tm.domain.services.processors.workflows.WorkflowUtils;
|
import zw.qantra.tm.domain.services.processors.workflows.WorkflowUtils;
|
||||||
import zw.qantra.tm.utils.LogUtils;
|
import zw.qantra.tm.utils.LogUtils;
|
||||||
@@ -48,6 +49,7 @@ public class TransactonController {
|
|||||||
private final WorkflowInstanceFactory workflowInstanceFactory;
|
private final WorkflowInstanceFactory workflowInstanceFactory;
|
||||||
private final WorkflowUtils workflowUtils;
|
private final WorkflowUtils workflowUtils;
|
||||||
private final ObjectStringMapper objectStringMapper;
|
private final ObjectStringMapper objectStringMapper;
|
||||||
|
private final CityWalletRemotePaymentProcessor cityWalletRemotePaymentProcessor;
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public ResponseEntity<Page<Transaction>> getAll(
|
public ResponseEntity<Page<Transaction>> getAll(
|
||||||
@@ -206,6 +208,16 @@ public class TransactonController {
|
|||||||
return ResponseEntity.ok(response);
|
return ResponseEntity.ok(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/velocity-otp")
|
||||||
|
public ResponseEntity<Transaction> updateOtp(@PathVariable UUID id, @RequestBody Transaction transaction) {
|
||||||
|
Transaction fetchTransaction = transactionService.findById(id);
|
||||||
|
if (fetchTransaction == null) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
fetchTransaction.setVerificationCode(transaction.getVerificationCode());
|
||||||
|
return ResponseEntity.ok(cityWalletRemotePaymentProcessor.updateVelocityTransactionOtp(fetchTransaction));
|
||||||
|
}
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
@PutMapping("/{id}")
|
||||||
public ResponseEntity<Transaction> update(@PathVariable UUID id, @RequestBody Transaction transaction) {
|
public ResponseEntity<Transaction> update(@PathVariable UUID id, @RequestBody Transaction transaction) {
|
||||||
if (!transactionService.getTransactionRepository().existsById(id)) {
|
if (!transactionService.getTransactionRepository().existsById(id)) {
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package zw.qantra.tm.domain.dtos.erp;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class VelocityAccountDto {
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private String accountNumber;
|
||||||
|
private String alternateAccountNumber;
|
||||||
|
private String parentAccountId;
|
||||||
|
private String type;
|
||||||
|
private String category;
|
||||||
|
private String ledger;
|
||||||
|
private Timestamp deactivatedAt;
|
||||||
|
private BigDecimal balance;
|
||||||
|
private String partyType;
|
||||||
|
private String party;
|
||||||
|
private String currency;
|
||||||
|
private String customerStringId;
|
||||||
|
private String companyStringId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package zw.qantra.tm.domain.dtos.erp;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class VelocityStatementDto {
|
||||||
|
private BigDecimal startBalance;
|
||||||
|
private BigDecimal endBalance;
|
||||||
|
private List<StatementItem> transactions;
|
||||||
|
private String accountName;
|
||||||
|
private String accountNumber;
|
||||||
|
private String startDate;
|
||||||
|
private String endDate;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public static class StatementItem {
|
||||||
|
private String name;
|
||||||
|
private String narration;
|
||||||
|
private String party;
|
||||||
|
private String company;
|
||||||
|
private String notes;
|
||||||
|
private Timestamp postingDate;
|
||||||
|
private BigDecimal amount;
|
||||||
|
private String account;
|
||||||
|
private String accountName;
|
||||||
|
private String currency;
|
||||||
|
private String reference;
|
||||||
|
private TransactionSide type;
|
||||||
|
private BigDecimal balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TransactionSide {
|
||||||
|
DEBIT, CREDIT
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package zw.qantra.tm.domain.models;
|
package zw.qantra.tm.domain.models;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@@ -17,6 +18,7 @@ import java.util.UUID;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class Transaction extends BaseEntity {
|
public class Transaction extends BaseEntity {
|
||||||
private String userId;
|
private String userId;
|
||||||
private String trace;
|
private String trace;
|
||||||
@@ -81,6 +83,7 @@ public class Transaction extends BaseEntity {
|
|||||||
private String orderId;
|
private String orderId;
|
||||||
private String orderTrace;
|
private String orderTrace;
|
||||||
private String orderTransactionTrace;
|
private String orderTransactionTrace;
|
||||||
|
private String orderTransactionId;
|
||||||
|
|
||||||
private String erpSalesRef;
|
private String erpSalesRef;
|
||||||
private String erpJournalRef;
|
private String erpJournalRef;
|
||||||
@@ -107,6 +110,8 @@ public class Transaction extends BaseEntity {
|
|||||||
@Column(columnDefinition = "TEXT")
|
@Column(columnDefinition = "TEXT")
|
||||||
private String targetUrl;
|
private String targetUrl;
|
||||||
private String sdkActionId;
|
private String sdkActionId;
|
||||||
|
private String verificationCode;
|
||||||
|
private Integer retries;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private Object additionalData;
|
private Object additionalData;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public class JobService {
|
|||||||
private final WorkflowInstanceService workflowInstanceService;
|
private final WorkflowInstanceService workflowInstanceService;
|
||||||
private final WorkflowUtils workflowUtils;
|
private final WorkflowUtils workflowUtils;
|
||||||
private final TransactionService transactionService;
|
private final TransactionService transactionService;
|
||||||
|
private final SettingService settingService;
|
||||||
|
|
||||||
public void checkOrphanedTransactions() {
|
public void checkOrphanedTransactions() {
|
||||||
List<Transaction> transactions = transactionService.getTransactionRepository()
|
List<Transaction> transactions = transactionService.getTransactionRepository()
|
||||||
@@ -42,6 +43,13 @@ public class JobService {
|
|||||||
for (Transaction transaction: transactions) {
|
for (Transaction transaction: transactions) {
|
||||||
attempts++;
|
attempts++;
|
||||||
try {
|
try {
|
||||||
|
int maxRetries = settingService.getIntegerSetting("MAX_RETRIES");
|
||||||
|
int retries = transaction.getRetries() == null ? 0 : transaction.getRetries();
|
||||||
|
|
||||||
|
if (retries >= maxRetries)
|
||||||
|
break;
|
||||||
|
|
||||||
|
transaction.setRetries(retries + 1);
|
||||||
// polling logic
|
// polling logic
|
||||||
WorkflowInstance update = new WorkflowInstance.Builder()
|
WorkflowInstance update = new WorkflowInstance.Builder()
|
||||||
.setId(transaction.getWorkflowId())
|
.setId(transaction.getWorkflowId())
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public class ProviderService {
|
|||||||
|
|
||||||
return products;
|
return products;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
log.error("Error fetching products: " + providerUid, e);
|
log.error("Error fetching products: {}", providerUid);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,19 @@ public class SettingService {
|
|||||||
return settingRepository;
|
return settingRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getIntegerSetting(String key) {
|
||||||
|
try {
|
||||||
|
Setting setting = settingRepository.findBySettingName(key);
|
||||||
|
if (setting != null) {
|
||||||
|
return Integer.parseInt(setting.getSettingValue());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} catch (Exception exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean getBooleanSetting(String key) {
|
public Boolean getBooleanSetting(String key) {
|
||||||
try {
|
try {
|
||||||
Setting setting = settingRepository.findBySettingName(key);
|
Setting setting = settingRepository.findBySettingName(key);
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package zw.qantra.tm.domain.services;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import zw.qantra.tm.domain.dtos.erp.VelocityAccountDto;
|
||||||
|
import zw.qantra.tm.domain.dtos.erp.VelocityStatementDto;
|
||||||
|
import zw.qantra.tm.utils.Utils;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VelocityAccountService {
|
||||||
|
|
||||||
|
private final VelocityPaymentService velocityPaymentService;
|
||||||
|
|
||||||
|
private static final String VELOCITY_API_ACCOUNT_BY_PHONE_PATH = "/accounts/phone/{currencyPhoneConcat}";
|
||||||
|
private static final String VELOCITY_API_STATEMENT_BY_PHONE_PATH = "/statements/phone/{currencyPhoneConcat}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches an account by the currency-phone concatenation.
|
||||||
|
*
|
||||||
|
* @param currencyPhoneConcat The concatenation of currency and phone (e.g. "USD+263771234567").
|
||||||
|
* @return VelocityAccountDto with account details.
|
||||||
|
*/
|
||||||
|
public VelocityAccountDto getAccountByPhone(String currencyPhoneConcat) {
|
||||||
|
try {
|
||||||
|
LinkedHashMap responseMap = velocityPaymentService.makeRequest(
|
||||||
|
HttpMethod.GET,
|
||||||
|
VELOCITY_API_ACCOUNT_BY_PHONE_PATH.replace("{currencyPhoneConcat}", currencyPhoneConcat),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if (responseMap == null || responseMap.isEmpty()) {
|
||||||
|
log.error("Error fetching account");
|
||||||
|
throw new IllegalStateException("Error fetching account");
|
||||||
|
}
|
||||||
|
return Utils.deepCopy(responseMap, VelocityAccountDto.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error fetching account by phone {}: {}", currencyPhoneConcat, e.getMessage(), e);
|
||||||
|
throw new IllegalStateException("Error fetching account: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches an account statement by the currency-phone concatenation and date range.
|
||||||
|
*
|
||||||
|
* @param currencyPhoneConcat The concatenation of currency and phone (e.g. "USD+263771234567").
|
||||||
|
* @param startDate The start date for the statement (e.g. "2025-01-01").
|
||||||
|
* @param endDate The end date for the statement (e.g. "2025-12-31").
|
||||||
|
* @return VelocityStatementDto with statement details.
|
||||||
|
*/
|
||||||
|
public VelocityStatementDto getStatementByPhone(String currencyPhoneConcat, String startDate, String endDate) {
|
||||||
|
try {
|
||||||
|
String path = VELOCITY_API_STATEMENT_BY_PHONE_PATH
|
||||||
|
.replace("{currencyPhoneConcat}", currencyPhoneConcat)
|
||||||
|
+ "?startDate=" + startDate + "&endDate=" + endDate;
|
||||||
|
|
||||||
|
LinkedHashMap responseMap = velocityPaymentService.makeRequest(
|
||||||
|
HttpMethod.GET,
|
||||||
|
path,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if (responseMap == null || responseMap.isEmpty()) {
|
||||||
|
log.error("Error fetching statement");
|
||||||
|
throw new IllegalStateException("Error fetching statement");
|
||||||
|
}
|
||||||
|
return Utils.deepCopy(responseMap, VelocityStatementDto.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error fetching statement for phone {} ({} - {}): {}",
|
||||||
|
currencyPhoneConcat, startDate, endDate, e.getMessage(), e);
|
||||||
|
throw new IllegalStateException("Error fetching statement: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,7 @@ public class VelocityPaymentService {
|
|||||||
private static final String VELOCITY_API_POLL_PAYMENT_PATH = "/transactions/poll/{traceId}";
|
private static final String VELOCITY_API_POLL_PAYMENT_PATH = "/transactions/poll/{traceId}";
|
||||||
private static final String VELOCITY_API_UPDATE_WORKFLOW_PATH = "/sales-orders/update-workflow/{traceId}";
|
private static final String VELOCITY_API_UPDATE_WORKFLOW_PATH = "/sales-orders/update-workflow/{traceId}";
|
||||||
private static final String VELOCITY_API_CUSTOMERS = "/customers";
|
private static final String VELOCITY_API_CUSTOMERS = "/customers";
|
||||||
|
private static final String VELOCITY_API_UPDATE_TRANSACTION_PATH = "/transactions/{id}";
|
||||||
|
|
||||||
public VelocityCustomerResponseDto createCustomer(RegisterRequest registerRequest) {
|
public VelocityCustomerResponseDto createCustomer(RegisterRequest registerRequest) {
|
||||||
VelocityCustomerDto payload = VelocityCustomerDto.builder()
|
VelocityCustomerDto payload = VelocityCustomerDto.builder()
|
||||||
@@ -170,14 +171,22 @@ public class VelocityPaymentService {
|
|||||||
LinkedHashMap response = makeRequest(
|
LinkedHashMap response = makeRequest(
|
||||||
HttpMethod.POST, VELOCITY_API_INITIATE_PAYMENT_PATH, payload);
|
HttpMethod.POST, VELOCITY_API_INITIATE_PAYMENT_PATH, payload);
|
||||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||||
|
|
||||||
|
if(body == null){
|
||||||
|
String errorMessage = (String) response.get("errorMessage");
|
||||||
|
log.error("Error initiating payment: {}", errorMessage);
|
||||||
|
throw new IllegalStateException("Error initiating payment: " + errorMessage);
|
||||||
|
}
|
||||||
String transactionStatus = (String) body.get("status");
|
String transactionStatus = (String) body.get("status");
|
||||||
String tranTrace = (String) body.get("trace");
|
String tranTrace = (String) body.get("trace");
|
||||||
|
String tranId = (String) body.get("id");
|
||||||
String transactionName = (String) body.get("name");
|
String transactionName = (String) body.get("name");
|
||||||
String redirectUrl = body.containsKey("redirectUrl") ? (String) body.get("redirectUrl") : null;
|
String redirectUrl = body.containsKey("redirectUrl") ? (String) body.get("redirectUrl") : null;
|
||||||
|
|
||||||
if ("SUCCESS".equalsIgnoreCase(transactionStatus)) {
|
if ("SUCCESS".equalsIgnoreCase(transactionStatus)) {
|
||||||
transaction.setErpSalesPaymentRef(transactionName);
|
transaction.setErpSalesPaymentRef(transactionName);
|
||||||
transaction.setOrderTransactionTrace(tranTrace);
|
transaction.setOrderTransactionTrace(tranTrace);
|
||||||
|
transaction.setOrderTransactionId(tranId);
|
||||||
transaction.setTargetUrl(redirectUrl);
|
transaction.setTargetUrl(redirectUrl);
|
||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
@@ -193,6 +202,14 @@ public class VelocityPaymentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Transaction pollPaymentStatus(Transaction transaction) {
|
public Transaction pollPaymentStatus(Transaction transaction) {
|
||||||
|
int maxRetries = settingService.getIntegerSetting("MAX_RETRIES");
|
||||||
|
int retries = transaction.getRetries() == null ? 0 : transaction.getRetries();
|
||||||
|
|
||||||
|
if (retries >= maxRetries)
|
||||||
|
return transaction;
|
||||||
|
|
||||||
|
transaction.setRetries(retries + 1);
|
||||||
|
|
||||||
LinkedHashMap response = makeRequest(
|
LinkedHashMap response = makeRequest(
|
||||||
HttpMethod.PUT,
|
HttpMethod.PUT,
|
||||||
VELOCITY_API_POLL_PAYMENT_PATH.replace("{traceId}", transaction.getOrderTransactionTrace()),
|
VELOCITY_API_POLL_PAYMENT_PATH.replace("{traceId}", transaction.getOrderTransactionTrace()),
|
||||||
@@ -200,14 +217,44 @@ public class VelocityPaymentService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||||
|
if(body == null){
|
||||||
|
String errorMessage = (String) response.get("errorMessage");
|
||||||
|
log.error("Error polling payment: {}", errorMessage);
|
||||||
|
throw new IllegalStateException("Error initiating payment: " + errorMessage);
|
||||||
|
}
|
||||||
|
transaction.setStatus(Status.valueOf((String) body.get("status")));
|
||||||
transaction.setPaymentStatus(Status.valueOf((String) body.get("paymentStatus")));
|
transaction.setPaymentStatus(Status.valueOf((String) body.get("paymentStatus")));
|
||||||
transaction.setPollingStatus(Status.valueOf((String) body.get("pollStatus")));
|
transaction.setPollingStatus(Status.valueOf((String) body.get("pollStatus")));
|
||||||
transaction.setDebitRef((String) body.get("debitRef"));
|
transaction.setDebitRef((String) body.get("debitRef"));
|
||||||
transaction.setPaymentProcessorRef((String) body.get("paymentProcessorRef"));
|
transaction.setPaymentProcessorRef((String) body.get("paymentProcessorRef"));
|
||||||
|
transaction.setResponseCode((String) body.get("responseCode"));
|
||||||
|
|
||||||
|
if (!transaction.getStatus().equals(Status.SUCCESS)) {
|
||||||
|
transaction.setErrorMessage((String) body.get("errorMessage"));
|
||||||
|
}
|
||||||
|
|
||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the OTP (additional data) on a transaction requiring manual verification.
|
||||||
|
* Equivalent to the Flutter/Dart {@code updateTransaction} method.
|
||||||
|
*
|
||||||
|
* @param id The transaction ID to update.
|
||||||
|
* @param otp The OTP value to set as additional data.
|
||||||
|
* @return A {@code LinkedHashMap} containing the Velocity API response.
|
||||||
|
*/
|
||||||
|
public LinkedHashMap updateTransaction(String id, String otp) {
|
||||||
|
Map<String, String> payload = new HashMap<>();
|
||||||
|
payload.put("additionalData", otp);
|
||||||
|
|
||||||
|
return makeRequest(
|
||||||
|
HttpMethod.PUT,
|
||||||
|
VELOCITY_API_UPDATE_TRANSACTION_PATH.replace("{id}", id),
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
public void updateSalesOrderWorkflow(Transaction transaction) {
|
public void updateSalesOrderWorkflow(Transaction transaction) {
|
||||||
LinkedHashMap response = makeRequest(
|
LinkedHashMap response = makeRequest(
|
||||||
@@ -226,7 +273,7 @@ public class VelocityPaymentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private LinkedHashMap makeRequest(HttpMethod method, String path, Object payload) {
|
LinkedHashMap makeRequest(HttpMethod method, String path, Object payload) {
|
||||||
long startNs = System.nanoTime();
|
long startNs = System.nanoTime();
|
||||||
ResponseEntity<LinkedHashMap> response;
|
ResponseEntity<LinkedHashMap> response;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package zw.qantra.tm.domain.services.processors.payments;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
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 zw.qantra.tm.domain.enums.Status;
|
||||||
|
import zw.qantra.tm.domain.models.Transaction;
|
||||||
|
import zw.qantra.tm.domain.services.SettingService;
|
||||||
|
import zw.qantra.tm.domain.services.TransactionService;
|
||||||
|
import zw.qantra.tm.domain.services.VelocityPaymentService;
|
||||||
|
import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||||
|
import zw.qantra.tm.rest.RestService;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
@Service("REQUEST_WALLET_REMOTE")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CityWalletRemotePaymentProcessor implements TransactionProcessorInterface {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(CityWalletRemotePaymentProcessor.class);
|
||||||
|
private final TransactionService transactionService;
|
||||||
|
private final SettingService settingService;
|
||||||
|
private final VelocityPaymentService velocityPaymentService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object process(Transaction transaction) throws Exception {
|
||||||
|
logger.info("processing transaction");
|
||||||
|
|
||||||
|
if(settingService.getBooleanSetting("SIMULATE_WALLET_SUCCESS")) {
|
||||||
|
transaction.setStatus(Status.SUCCESS);
|
||||||
|
transaction.setResponseCode("02");
|
||||||
|
transaction.setPaymentProcessorRef(RandomStringUtils.randomNumeric(10));
|
||||||
|
transaction.setDebitRef(RandomStringUtils.randomNumeric(10));
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
transaction = velocityPaymentService.processPayment(transaction);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||||
|
transaction.setStatus(Status.FAILED);
|
||||||
|
transaction.setResponseCode("99");
|
||||||
|
transaction.setSystemErrorMessage("Network error: " + e.getMessage());
|
||||||
|
transaction.setErrorMessage("Payment failed. Please try again.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactionService.save(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object reverse(Transaction transaction) {
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object poll(Transaction transaction) throws Exception {
|
||||||
|
logger.info("polling transaction");
|
||||||
|
|
||||||
|
if(settingService.getBooleanSetting("SIMULATE_WALLET_SUCCESS")) {
|
||||||
|
transaction.setStatus(Status.SUCCESS);
|
||||||
|
transaction.setResponseCode("02");
|
||||||
|
transaction.setTargetUrl("/home");
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
transaction = velocityPaymentService.pollPaymentStatus(transaction);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||||
|
transaction.setStatus(Status.FAILED);
|
||||||
|
transaction.setResponseCode("99");
|
||||||
|
transaction.setSystemErrorMessage("Network error: " + e.getMessage());
|
||||||
|
transaction.setErrorMessage("Payment failed. Please try again.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactionService.save(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transaction updateVelocityTransactionOtp(Transaction transaction) {
|
||||||
|
String code = transaction.getVerificationCode();
|
||||||
|
|
||||||
|
try {
|
||||||
|
velocityPaymentService.updateTransaction(transaction.getOrderTransactionId(), code);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
logger.error("Network error during payment update: {}", e.getMessage(), e);
|
||||||
|
transaction.setStatus(Status.FAILED);
|
||||||
|
transaction.setResponseCode("99");
|
||||||
|
transaction.setSystemErrorMessage("Network error: " + e.getMessage());
|
||||||
|
transaction.setErrorMessage("Payment failed. Please try again.");
|
||||||
|
}
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -23,20 +23,10 @@ import zw.qantra.tm.rest.RestService;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class EcocashRemotePaymentProcessor implements TransactionProcessorInterface {
|
public class EcocashRemotePaymentProcessor implements TransactionProcessorInterface {
|
||||||
private final Logger logger = LoggerFactory.getLogger(EcocashRemotePaymentProcessor.class);
|
private final Logger logger = LoggerFactory.getLogger(EcocashRemotePaymentProcessor.class);
|
||||||
private final RestService restService;
|
|
||||||
private final TransactionService transactionService;
|
private final TransactionService transactionService;
|
||||||
private final SettingService settingService;
|
private final SettingService settingService;
|
||||||
private final VelocityPaymentService velocityPaymentService;
|
private final VelocityPaymentService velocityPaymentService;
|
||||||
|
|
||||||
@Value("${sbz.aggregator.encryption-key}")
|
|
||||||
private String encryptionKey;
|
|
||||||
@Value("${sbz.aggregator.client-id}")
|
|
||||||
private String clientId;
|
|
||||||
@Value("${sbz.aggregator.client-secret}")
|
|
||||||
private String clientSecret;
|
|
||||||
@Value("${steward.payment.processor.url}")
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object process(Transaction transaction) throws Exception {
|
public Object process(Transaction transaction) throws Exception {
|
||||||
logger.info("processing transaction");
|
logger.info("processing transaction");
|
||||||
@@ -81,11 +71,6 @@ public class EcocashRemotePaymentProcessor implements TransactionProcessorInterf
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
transaction = velocityPaymentService.pollPaymentStatus(transaction);
|
transaction = velocityPaymentService.pollPaymentStatus(transaction);
|
||||||
transaction.setStatus(Status.SUCCESS);
|
|
||||||
transaction.setResponseCode("00");
|
|
||||||
|
|
||||||
transactionService.save(transaction);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||||
@@ -95,7 +80,7 @@ public class EcocashRemotePaymentProcessor implements TransactionProcessorInterf
|
|||||||
transaction.setErrorMessage("Payment failed. Please try again.");
|
transaction.setErrorMessage("Payment failed. Please try again.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return transaction;
|
return transactionService.save(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHash(String originalString){
|
public String getHash(String originalString){
|
||||||
|
|||||||
@@ -31,22 +31,10 @@ import java.util.Random;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
||||||
private final Logger logger = LoggerFactory.getLogger(MPGSWebPaymentProcessor.class);
|
private final Logger logger = LoggerFactory.getLogger(MPGSWebPaymentProcessor.class);
|
||||||
private final RestService restService;
|
|
||||||
private final TransactionService transactionService;
|
private final TransactionService transactionService;
|
||||||
private final SettingService settingService;
|
private final SettingService settingService;
|
||||||
private final VelocityPaymentService velocityPaymentService;
|
private final VelocityPaymentService velocityPaymentService;
|
||||||
|
|
||||||
@Value("${sbz.aggregator.encryption-key}")
|
|
||||||
private String encryptionKey;
|
|
||||||
@Value("${sbz.aggregator.client-id}")
|
|
||||||
private String clientId;
|
|
||||||
@Value("${sbz.aggregator.client-secret}")
|
|
||||||
private String clientSecret;
|
|
||||||
@Value("${steward.payment.processor.url}")
|
|
||||||
private String url;
|
|
||||||
@Value("${mpgs.return-url}")
|
|
||||||
private String returnUrl;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object process(Transaction transaction) throws Exception {
|
public Object process(Transaction transaction) throws Exception {
|
||||||
logger.info("processing transaction");
|
logger.info("processing transaction");
|
||||||
@@ -88,11 +76,6 @@ public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
|||||||
try {
|
try {
|
||||||
transaction = velocityPaymentService.pollPaymentStatus(transaction);
|
transaction = velocityPaymentService.pollPaymentStatus(transaction);
|
||||||
|
|
||||||
transaction.setStatus(transaction.getStatus());
|
|
||||||
transaction.setResponseCode("00");
|
|
||||||
|
|
||||||
transactionService.save(transaction);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||||
@@ -102,7 +85,7 @@ public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
|||||||
transaction.setErrorMessage("Payment failed. Please try again");
|
transaction.setErrorMessage("Payment failed. Please try again");
|
||||||
}
|
}
|
||||||
|
|
||||||
return transaction;
|
return transactionService.save(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -24,6 +24,16 @@ public class PaymentProcessorSeeder implements Seeder {
|
|||||||
@Override
|
@Override
|
||||||
public void seed() {
|
public void seed() {
|
||||||
List<PaymentProcessor> processors = Arrays.asList(
|
List<PaymentProcessor> processors = Arrays.asList(
|
||||||
|
PaymentProcessor.builder()
|
||||||
|
.name("CityWallet")
|
||||||
|
.label("WALLET")
|
||||||
|
.type("GATEWAY")
|
||||||
|
.image("city.png")
|
||||||
|
.accountFieldName("phoneNumber")
|
||||||
|
.accountFieldLabel("Wallet Phone Number")
|
||||||
|
.description("Pay using your CityWallet")
|
||||||
|
.authType("REMOTE")
|
||||||
|
.build(),
|
||||||
PaymentProcessor.builder()
|
PaymentProcessor.builder()
|
||||||
.name("Ecocash")
|
.name("Ecocash")
|
||||||
.label("ECOCASH")
|
.label("ECOCASH")
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ ecocash.url=https://developers.ecocash.co.zw/api/ecocash_pay/api/v2/payment/inst
|
|||||||
|
|
||||||
#velocity.api.base-url=https://api.velocityafrica.net
|
#velocity.api.base-url=https://api.velocityafrica.net
|
||||||
#velocity.api.api-key=z5WdSlItIhYL6nd7rxzf-jFdKN3jJyL1LubhDFBvXmc
|
#velocity.api.api-key=z5WdSlItIhYL6nd7rxzf-jFdKN3jJyL1LubhDFBvXmc
|
||||||
#velocity.api.base-url=http://localhost:9005
|
velocity.api.base-url=http://localhost:6975
|
||||||
#velocity.api.api-key=gH13nirZdUQdqC9impgzTzqEqv-jdbLOTx_HD5fQr_A
|
velocity.api.api-key=gH13nirZdUQdqC9impgzTzqEqv-jdbLOTx_HD5fQr_A
|
||||||
velocity.api.cancel-url=http://localhost:9005/poll
|
velocity.api.cancel-url=http://localhost:9005/poll
|
||||||
velocity.api.success-url=http://localhost:9005/poll
|
velocity.api.success-url=http://localhost:9005/poll
|
||||||
|
|
||||||
|
|||||||
@@ -1,99 +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="1780904354124-3">
|
<changeSet author="khoza (generated)" id="1781170534745-3">
|
||||||
<createTable tableName="group_batch">
|
|
||||||
<column name="id" type="UUID">
|
|
||||||
<constraints nullable="false" primaryKey="true" primaryKeyName="group_batchPK"/>
|
|
||||||
</column>
|
|
||||||
<column name="created_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column defaultValueBoolean="false" name="deleted" type="BOOLEAN"/>
|
|
||||||
<column name="updated_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="completed_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="confirm_idempotency_key" type="VARCHAR(255)"/>
|
|
||||||
<column name="confirm_started_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="count" type="INTEGER"/>
|
|
||||||
<column name="currency" type="VARCHAR(255)"/>
|
|
||||||
<column name="description" type="VARCHAR(255)"/>
|
|
||||||
<column name="failed_count" type="INTEGER"/>
|
|
||||||
<column name="integration_started_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="payment_processor_image" type="VARCHAR(255)"/>
|
|
||||||
<column name="payment_processor_label" type="VARCHAR(255)"/>
|
|
||||||
<column name="payment_processor_name" type="VARCHAR(255)"/>
|
|
||||||
<column name="payment_reference" type="VARCHAR(255)"/>
|
|
||||||
<column name="payment_transaction_id" type="UUID"/>
|
|
||||||
<column name="poll_idempotency_key" type="VARCHAR(255)"/>
|
|
||||||
<column name="poll_started_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="recipient_group_id" type="UUID"/>
|
|
||||||
<column name="request_idempotency_key" type="VARCHAR(255)"/>
|
|
||||||
<column name="request_started_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="requested_by" type="VARCHAR(255)"/>
|
|
||||||
<column name="result_file_url" type="TEXT"/>
|
|
||||||
<column name="status" type="VARCHAR(255)"/>
|
|
||||||
<column name="successful_count" type="INTEGER"/>
|
|
||||||
<column name="transaction_template" type="TEXT"/>
|
|
||||||
<column name="user_id" type="VARCHAR(255)"/>
|
|
||||||
<column name="value" type="numeric(38, 2)"/>
|
|
||||||
<column name="workflow_id" type="BIGINT"/>
|
|
||||||
</createTable>
|
|
||||||
</changeSet>
|
|
||||||
<changeSet author="khoza (generated)" id="1780904354124-4">
|
|
||||||
<createTable tableName="group_batch_item">
|
|
||||||
<column name="id" type="UUID">
|
|
||||||
<constraints nullable="false" primaryKey="true" primaryKeyName="group_batch_itemPK"/>
|
|
||||||
</column>
|
|
||||||
<column name="created_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column defaultValueBoolean="false" name="deleted" type="BOOLEAN"/>
|
|
||||||
<column name="updated_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="amount" type="numeric(38, 2)"/>
|
|
||||||
<column name="confirm_error" type="TEXT"/>
|
|
||||||
<column name="confirm_status" type="VARCHAR(255)"/>
|
|
||||||
<column name="group_batch_id" type="UUID"/>
|
|
||||||
<column name="integration_error" type="TEXT"/>
|
|
||||||
<column name="integration_status" type="VARCHAR(255)"/>
|
|
||||||
<column name="recipient_id" type="UUID"/>
|
|
||||||
<column name="recipient_name" type="VARCHAR(255)"/>
|
|
||||||
<column name="recipient_phone" type="VARCHAR(255)"/>
|
|
||||||
<column name="status" type="VARCHAR(255)"/>
|
|
||||||
<column name="transaction_id" type="UUID"/>
|
|
||||||
</createTable>
|
|
||||||
</changeSet>
|
|
||||||
<changeSet author="khoza (generated)" id="1780904354124-5">
|
|
||||||
<createTable tableName="recipient_group">
|
|
||||||
<column name="id" type="UUID">
|
|
||||||
<constraints nullable="false" primaryKey="true" primaryKeyName="recipient_groupPK"/>
|
|
||||||
</column>
|
|
||||||
<column name="created_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column defaultValueBoolean="false" name="deleted" type="BOOLEAN"/>
|
|
||||||
<column name="updated_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="description" type="VARCHAR(255)"/>
|
|
||||||
<column name="name" type="VARCHAR(255)"/>
|
|
||||||
<column name="user_id" type="VARCHAR(255)"/>
|
|
||||||
</createTable>
|
|
||||||
</changeSet>
|
|
||||||
<changeSet author="khoza (generated)" id="1780904354124-6">
|
|
||||||
<createTable tableName="recipient_group_member">
|
|
||||||
<column name="id" type="UUID">
|
|
||||||
<constraints nullable="false" primaryKey="true" primaryKeyName="recipient_group_memberPK"/>
|
|
||||||
</column>
|
|
||||||
<column name="created_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column defaultValueBoolean="false" name="deleted" type="BOOLEAN"/>
|
|
||||||
<column name="updated_at" type="TIMESTAMP(6) WITHOUT TIME ZONE"/>
|
|
||||||
<column name="account" type="VARCHAR(255)"/>
|
|
||||||
<column name="recipient_group_id" type="UUID"/>
|
|
||||||
<column name="recipient_uid" type="UUID"/>
|
|
||||||
<column name="user_id" type="VARCHAR(255)"/>
|
|
||||||
<column name="recipient_id" type="UUID"/>
|
|
||||||
</createTable>
|
|
||||||
</changeSet>
|
|
||||||
<changeSet author="khoza (generated)" id="1780904354124-7">
|
|
||||||
<addColumn tableName="transaction">
|
<addColumn tableName="transaction">
|
||||||
<column name="party_type" type="smallint"/>
|
<column name="retries" type="integer"/>
|
||||||
</addColumn>
|
</addColumn>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="khoza (generated)" id="1780904354124-8">
|
|
||||||
<addForeignKeyConstraint baseColumnNames="recipient_id" baseTableName="recipient_group_member" constraintName="FK50dbg59nfkur42vjx44xc4d6v" deferrable="false" initiallyDeferred="false" referencedColumnNames="id" referencedTableName="recipient" validate="true"/>
|
|
||||||
</changeSet>
|
|
||||||
<changeSet author="khoza (generated)" id="1780904354124-9">
|
|
||||||
<addForeignKeyConstraint baseColumnNames="transaction_id" baseTableName="group_batch_item" constraintName="FK8n8fahugsdfs2aue2ad34u69f" deferrable="false" initiallyDeferred="false" referencedColumnNames="id" referencedTableName="transaction" validate="true"/>
|
|
||||||
</changeSet>
|
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
Reference in New Issue
Block a user