polishing the workspace migration
This commit is contained in:
@@ -39,8 +39,7 @@ public class SecurityConfig {
|
|||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.authenticationProvider(authenticationProvider(userService))
|
.authenticationProvider(authenticationProvider(userService))
|
||||||
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
|
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
.formLogin(withDefaults());
|
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import zw.qantra.tm.domain.dtos.erp.VelocityAccountDto;
|
import zw.qantra.tm.domain.dtos.erp.VelocityAccountDto;
|
||||||
import zw.qantra.tm.domain.dtos.erp.VelocityStatementDto;
|
import zw.qantra.tm.domain.dtos.erp.VelocityStatementDto;
|
||||||
|
import zw.qantra.tm.domain.models.Workspace;
|
||||||
import zw.qantra.tm.domain.services.VelocityAccountService;
|
import zw.qantra.tm.domain.services.VelocityAccountService;
|
||||||
|
import zw.qantra.tm.domain.services.WorkspaceService;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/accounts")
|
@RequestMapping("/accounts")
|
||||||
@@ -14,12 +18,17 @@ import zw.qantra.tm.domain.services.VelocityAccountService;
|
|||||||
public class AccountController {
|
public class AccountController {
|
||||||
|
|
||||||
private final VelocityAccountService velocityAccountService;
|
private final VelocityAccountService velocityAccountService;
|
||||||
|
private final WorkspaceService workspaceService;
|
||||||
|
|
||||||
@GetMapping("/phone/{currencyPhoneConcat}")
|
@GetMapping("/{workspaceId}/balance/{currency}")
|
||||||
@PreAuthorize("hasRole('ACCOUNT_READ')")
|
public ResponseEntity<VelocityAccountDto> getAccount(
|
||||||
public ResponseEntity<VelocityAccountDto> getAccountByPhone(
|
@PathVariable UUID workspaceId,
|
||||||
@PathVariable String currencyPhoneConcat) {
|
@PathVariable String currency
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
|
Workspace workspace = workspaceService.getWorkspace(workspaceId)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("Workspace not found"));
|
||||||
|
String currencyPhoneConcat = currency + workspace.getPhone();
|
||||||
VelocityAccountDto account = velocityAccountService.getAccountByPhone(currencyPhoneConcat);
|
VelocityAccountDto account = velocityAccountService.getAccountByPhone(currencyPhoneConcat);
|
||||||
return ResponseEntity.ok(account);
|
return ResponseEntity.ok(account);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -27,13 +36,16 @@ public class AccountController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/phone/{currencyPhoneConcat}/statement")
|
@GetMapping("/{workspaceId}/statement/{currency}")
|
||||||
@PreAuthorize("hasRole('ACCOUNT_READ')")
|
public ResponseEntity<VelocityStatementDto> getStatement(
|
||||||
public ResponseEntity<VelocityStatementDto> getStatementByPhone(
|
@PathVariable UUID workspaceId,
|
||||||
@PathVariable String currencyPhoneConcat,
|
@PathVariable String currency,
|
||||||
@RequestParam String startDate,
|
@RequestParam String startDate,
|
||||||
@RequestParam String endDate) {
|
@RequestParam String endDate) {
|
||||||
try {
|
try {
|
||||||
|
Workspace workspace = workspaceService.getWorkspace(workspaceId)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("Workspace not found"));
|
||||||
|
String currencyPhoneConcat = currency + workspace.getPhone();
|
||||||
VelocityStatementDto statement = velocityAccountService.getStatementByPhone(
|
VelocityStatementDto statement = velocityAccountService.getStatementByPhone(
|
||||||
currencyPhoneConcat, startDate, endDate);
|
currencyPhoneConcat, startDate, endDate);
|
||||||
return ResponseEntity.ok(statement);
|
return ResponseEntity.ok(statement);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/public/group-batches")
|
@RequestMapping("/group-batches")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GroupBatchController {
|
public class GroupBatchController {
|
||||||
private final GroupBatchService groupBatchService;
|
private final GroupBatchService groupBatchService;
|
||||||
@@ -32,7 +32,7 @@ public class GroupBatchController {
|
|||||||
public ResponseEntity findAll(
|
public ResponseEntity findAll(
|
||||||
@And({
|
@And({
|
||||||
@Spec(path = "recipientGroupId", defaultVal = "null", spec = Equal.class),
|
@Spec(path = "recipientGroupId", defaultVal = "null", spec = Equal.class),
|
||||||
@Spec(path = "userId", spec = Equal.class),
|
@Spec(path = "workspaceId", spec = Equal.class),
|
||||||
@Spec(path = "status", spec = Equal.class),
|
@Spec(path = "status", spec = Equal.class),
|
||||||
@Spec(path = "currency", spec = Equal.class),
|
@Spec(path = "currency", spec = Equal.class),
|
||||||
})Specification<GroupBatch> spec, Pageable pageable){
|
})Specification<GroupBatch> spec, Pageable pageable){
|
||||||
@@ -56,7 +56,7 @@ public class GroupBatchController {
|
|||||||
@RequestBody GroupBatchTriggerRequest request) {
|
@RequestBody GroupBatchTriggerRequest request) {
|
||||||
return ResponseEntity.ok(groupBatchService.triggerConfirm(
|
return ResponseEntity.ok(groupBatchService.triggerConfirm(
|
||||||
batchId,
|
batchId,
|
||||||
request.getUserId(),
|
request.getWorkspaceId(),
|
||||||
request.getIdempotencyKey()));
|
request.getIdempotencyKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ public class GroupBatchController {
|
|||||||
@RequestBody GroupBatchTriggerRequest request) {
|
@RequestBody GroupBatchTriggerRequest request) {
|
||||||
Object response = groupBatchService.triggerRequest(
|
Object response = groupBatchService.triggerRequest(
|
||||||
batchId,
|
batchId,
|
||||||
request.getUserId(),
|
request.getWorkspaceId(),
|
||||||
request.getAuthType(),
|
request.getAuthType(),
|
||||||
request.getIdempotencyKey());
|
request.getIdempotencyKey());
|
||||||
return ResponseEntity.ok(response);
|
return ResponseEntity.ok(response);
|
||||||
@@ -76,14 +76,14 @@ public class GroupBatchController {
|
|||||||
@RequestBody GroupBatchTriggerRequest request) {
|
@RequestBody GroupBatchTriggerRequest request) {
|
||||||
return ResponseEntity.ok(groupBatchService.triggerPoll(
|
return ResponseEntity.ok(groupBatchService.triggerPoll(
|
||||||
batchId,
|
batchId,
|
||||||
request.getUserId(),
|
request.getWorkspaceId(),
|
||||||
request.getIdempotencyKey()));
|
request.getIdempotencyKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{batchId}")
|
@GetMapping("/{batchId}")
|
||||||
public ResponseEntity<GroupBatch> getBatch(@PathVariable UUID batchId,
|
public ResponseEntity<GroupBatch> getBatch(@PathVariable UUID batchId,
|
||||||
@RequestParam String userId) {
|
@RequestParam UUID workspaceId) {
|
||||||
return ResponseEntity.ok(groupBatchService.getBatch(batchId, userId));
|
return ResponseEntity.ok(groupBatchService.getBatch(batchId, workspaceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/items")
|
@GetMapping("/items")
|
||||||
@@ -101,21 +101,21 @@ public class GroupBatchController {
|
|||||||
@RequestBody GroupBatchItemUpdateRequest.ListWrapper wrapper) {
|
@RequestBody GroupBatchItemUpdateRequest.ListWrapper wrapper) {
|
||||||
return ResponseEntity.ok(groupBatchService.updateBatchItems(
|
return ResponseEntity.ok(groupBatchService.updateBatchItems(
|
||||||
batchId,
|
batchId,
|
||||||
wrapper.getUserId(),
|
wrapper.getWorkspaceId(),
|
||||||
wrapper.getItems()));
|
wrapper.getItems()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{batchId}")
|
@DeleteMapping("/{batchId}")
|
||||||
public ResponseEntity<Void> deleteBatch(@PathVariable UUID batchId,
|
public ResponseEntity<Void> deleteBatch(@PathVariable UUID batchId,
|
||||||
@RequestParam String userId) {
|
@RequestParam UUID workspaceId) {
|
||||||
groupBatchService.deleteBatch(batchId, userId);
|
groupBatchService.deleteBatch(batchId, workspaceId);
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{batchId}/report")
|
@GetMapping("/{batchId}/report")
|
||||||
public ResponseEntity<Map<String, Object>> downloadBatchReport(@PathVariable UUID batchId,
|
public ResponseEntity<Map<String, Object>> downloadBatchReport(@PathVariable UUID batchId,
|
||||||
@RequestParam String userId) {
|
@RequestParam UUID workspaceId) {
|
||||||
BatchReportService.BatchReportResult result = batchReportService.generateBatchReport(batchId, userId);
|
BatchReportService.BatchReportResult result = batchReportService.generateBatchReport(batchId, workspaceId);
|
||||||
return ResponseEntity.ok(Map.of(
|
return ResponseEntity.ok(Map.of(
|
||||||
"fileUrl", result.fileUrl(),
|
"fileUrl", result.fileUrl(),
|
||||||
"alreadyExisted", result.alreadyExisted()
|
"alreadyExisted", result.alreadyExisted()
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ package zw.qantra.tm.domain.controllers;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.kaczmarzyk.spring.data.jpa.domain.Equal;
|
import net.kaczmarzyk.spring.data.jpa.domain.Equal;
|
||||||
import net.kaczmarzyk.spring.data.jpa.domain.Like;
|
|
||||||
import net.kaczmarzyk.spring.data.jpa.web.annotation.Spec;
|
import net.kaczmarzyk.spring.data.jpa.web.annotation.Spec;
|
||||||
import net.kaczmarzyk.spring.data.jpa.web.annotation.Or;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -22,22 +21,23 @@ public class RecipientController {
|
|||||||
|
|
||||||
private final RecipientService recipientService;
|
private final RecipientService recipientService;
|
||||||
|
|
||||||
@GetMapping("/search")
|
@GetMapping
|
||||||
public ResponseEntity<List<Recipient>> searchRecipients(
|
public ResponseEntity searchRecipients(
|
||||||
@And({
|
@And({
|
||||||
@Spec(path = "name", spec = Equal.class),
|
@Spec(path = "name", spec = Equal.class),
|
||||||
@Spec(path = "email", spec = Equal.class),
|
@Spec(path = "email", spec = Equal.class),
|
||||||
@Spec(path = "phoneNumber", spec = Equal.class),
|
@Spec(path = "phoneNumber", spec = Equal.class),
|
||||||
@Spec(path = "account", spec = Equal.class),
|
@Spec(path = "account", spec = Equal.class),
|
||||||
@Spec(path = "latestProviderLabel", spec = Equal.class),
|
@Spec(path = "latestProviderLabel", spec = Equal.class),
|
||||||
@Spec(path = "userId", defaultVal = "null", spec = Equal.class)
|
@Spec(path = "userId", spec = Equal.class),
|
||||||
}) Specification<Recipient> specification) {
|
@Spec(path = "workspaceId", defaultVal = "null", spec = Equal.class)
|
||||||
return ResponseEntity.ok(recipientService.searchRecipients(specification));
|
}) Specification<Recipient> specification, Pageable pageable) {
|
||||||
|
return ResponseEntity.ok(recipientService.findAllRecipients(specification, pageable));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{account}/user/{userId}")
|
@GetMapping("/{account}/workspace/{workspaceId}")
|
||||||
public ResponseEntity<Recipient> getRecipient(@PathVariable String account, @PathVariable String userId) {
|
public ResponseEntity<Recipient> getRecipient(@PathVariable String account, @PathVariable UUID workspaceId) {
|
||||||
List<Recipient> recipients = recipientService.getRecipient(account, userId);
|
List<Recipient> recipients = recipientService.getRecipient(account, workspaceId);
|
||||||
if(recipients.size() > 0){
|
if(recipients.size() > 0){
|
||||||
return ResponseEntity.ok(recipients.get(0));
|
return ResponseEntity.ok(recipients.get(0));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import java.util.List;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/public/recipient-groups")
|
@RequestMapping("/recipient-groups")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RecipientGroupController {
|
public class RecipientGroupController {
|
||||||
private final RecipientGroupService recipientGroupService;
|
private final RecipientGroupService recipientGroupService;
|
||||||
@@ -34,7 +34,7 @@ public class RecipientGroupController {
|
|||||||
public ResponseEntity findAll(
|
public ResponseEntity findAll(
|
||||||
@And({
|
@And({
|
||||||
@Spec(path = "name", spec = EqualIgnoreCase.class),
|
@Spec(path = "name", spec = EqualIgnoreCase.class),
|
||||||
@Spec(path = "userId", defaultVal = "null", spec = Equal.class)
|
@Spec(path = "workspaceId", defaultVal = "null", spec = Equal.class)
|
||||||
})Specification<RecipientGroup> spec, Pageable pageable) {
|
})Specification<RecipientGroup> spec, Pageable pageable) {
|
||||||
return ResponseEntity.ok(recipientGroupService.findAll(spec, pageable));
|
return ResponseEntity.ok(recipientGroupService.findAll(spec, pageable));
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,7 @@ public class RecipientGroupController {
|
|||||||
RecipientGroup group = RecipientGroup.builder()
|
RecipientGroup group = RecipientGroup.builder()
|
||||||
.name(request.getName())
|
.name(request.getName())
|
||||||
.description(request.getDescription())
|
.description(request.getDescription())
|
||||||
|
.workspaceId(request.getWorkspaceId())
|
||||||
.userId(request.getUserId())
|
.userId(request.getUserId())
|
||||||
.build();
|
.build();
|
||||||
return ResponseEntity.ok(recipientGroupService.create(group, request.getRecipients()));
|
return ResponseEntity.ok(recipientGroupService.create(group, request.getRecipients()));
|
||||||
@@ -56,7 +57,7 @@ public class RecipientGroupController {
|
|||||||
@RequestParam(value = "description", required = false) String description,
|
@RequestParam(value = "description", required = false) String description,
|
||||||
@RequestParam(value = "requestedBy", required = false) String requestedBy,
|
@RequestParam(value = "requestedBy", required = false) String requestedBy,
|
||||||
@RequestParam(value = "currency", required = false) String currency,
|
@RequestParam(value = "currency", required = false) String currency,
|
||||||
@RequestParam("userId") String userId) {
|
@RequestParam("workspaceId") UUID workspaceId) {
|
||||||
|
|
||||||
GroupCreateFromFileRequest request = new GroupCreateFromFileRequest();
|
GroupCreateFromFileRequest request = new GroupCreateFromFileRequest();
|
||||||
request.setGroupName(groupName.trim());
|
request.setGroupName(groupName.trim());
|
||||||
@@ -64,7 +65,7 @@ public class RecipientGroupController {
|
|||||||
request.setRequestedBy(requestedBy);
|
request.setRequestedBy(requestedBy);
|
||||||
request.setCurrency(currency);
|
request.setCurrency(currency);
|
||||||
|
|
||||||
return ResponseEntity.ok(recipientGroupService.createFromFile(file, request, userId));
|
return ResponseEntity.ok(recipientGroupService.createFromFile(file, request, workspaceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/update/{groupId}")
|
@PutMapping("/update/{groupId}")
|
||||||
@@ -72,15 +73,15 @@ public class RecipientGroupController {
|
|||||||
@RequestBody RecipientGroupUpdateRequest request) {
|
@RequestBody RecipientGroupUpdateRequest request) {
|
||||||
return ResponseEntity.ok(recipientGroupService.update(
|
return ResponseEntity.ok(recipientGroupService.update(
|
||||||
groupId,
|
groupId,
|
||||||
request.getUserId(),
|
request.getWorkspaceId(),
|
||||||
request.getName(),
|
request.getName(),
|
||||||
request.getDescription()));
|
request.getDescription()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete/{groupId}")
|
@DeleteMapping("/delete/{groupId}")
|
||||||
public ResponseEntity<Void> delete(@PathVariable UUID groupId,
|
public ResponseEntity<Void> delete(@PathVariable UUID groupId,
|
||||||
@RequestParam String userId) {
|
@RequestParam UUID workspaceId) {
|
||||||
recipientGroupService.delete(groupId, userId);
|
recipientGroupService.delete(groupId, workspaceId);
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,15 +90,15 @@ public class RecipientGroupController {
|
|||||||
@RequestBody GroupMemberRequest request) {
|
@RequestBody GroupMemberRequest request) {
|
||||||
return ResponseEntity.ok(recipientGroupService.addMembersByIds(
|
return ResponseEntity.ok(recipientGroupService.addMembersByIds(
|
||||||
groupId,
|
groupId,
|
||||||
request.getUserId(),
|
request.getWorkspaceId(),
|
||||||
request.getRecipientIds()));
|
request.getRecipientIds()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{groupId}/members/{recipientId}")
|
@DeleteMapping("/{groupId}/members/{recipientId}")
|
||||||
public ResponseEntity<Void> removeMember(@PathVariable UUID groupId,
|
public ResponseEntity<Void> removeMember(@PathVariable UUID groupId,
|
||||||
@PathVariable UUID recipientId,
|
@PathVariable UUID recipientId,
|
||||||
@RequestParam String userId) {
|
@RequestParam UUID workspaceId) {
|
||||||
recipientGroupService.removeMember(groupId, recipientId, userId);
|
recipientGroupService.removeMember(groupId, recipientId, workspaceId);
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import zw.qantra.tm.domain.enums.RequestType;
|
|||||||
import zw.qantra.tm.domain.models.Transaction;
|
import zw.qantra.tm.domain.models.Transaction;
|
||||||
import zw.qantra.tm.domain.services.NotificationService;
|
import zw.qantra.tm.domain.services.NotificationService;
|
||||||
import zw.qantra.tm.domain.services.TransactionService;
|
import zw.qantra.tm.domain.services.TransactionService;
|
||||||
|
import zw.qantra.tm.domain.services.WorkspaceMigrationService;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/test")
|
@RequestMapping("/test")
|
||||||
@@ -20,6 +21,7 @@ import zw.qantra.tm.domain.services.TransactionService;
|
|||||||
public class TestController {
|
public class TestController {
|
||||||
private final NotificationService notificationService;
|
private final NotificationService notificationService;
|
||||||
private final TransactionService transactionService;
|
private final TransactionService transactionService;
|
||||||
|
private final WorkspaceMigrationService workspaceMigrationService;
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
|
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
|
||||||
|
|
||||||
@@ -59,4 +61,10 @@ public class TestController {
|
|||||||
public ResponseEntity<String> publicEndpoint() {
|
public ResponseEntity<String> publicEndpoint() {
|
||||||
return ResponseEntity.ok("This is a public endpoint - no authentication required!");
|
return ResponseEntity.ok("This is a public endpoint - no authentication required!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/migrate-workspaces")
|
||||||
|
public ResponseEntity<WorkspaceMigrationService.MigrationResult> migrateWorkspaces() {
|
||||||
|
WorkspaceMigrationService.MigrationResult result = workspaceMigrationService.migrate();
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import io.nflow.engine.workflow.instance.WorkflowInstanceAction;
|
|||||||
import io.nflow.engine.workflow.instance.WorkflowInstanceFactory;
|
import io.nflow.engine.workflow.instance.WorkflowInstanceFactory;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.kaczmarzyk.spring.data.jpa.domain.Equal;
|
import net.kaczmarzyk.spring.data.jpa.domain.Equal;
|
||||||
|
import net.kaczmarzyk.spring.data.jpa.domain.In;
|
||||||
import net.kaczmarzyk.spring.data.jpa.web.annotation.Or;
|
import net.kaczmarzyk.spring.data.jpa.web.annotation.Or;
|
||||||
import net.kaczmarzyk.spring.data.jpa.web.annotation.Spec;
|
import net.kaczmarzyk.spring.data.jpa.web.annotation.Spec;
|
||||||
import net.kaczmarzyk.spring.data.jpa.web.annotation.Conjunction;
|
import net.kaczmarzyk.spring.data.jpa.web.annotation.Conjunction;
|
||||||
@@ -72,20 +73,22 @@ public class TransactonController {
|
|||||||
@Spec(path = "amount", spec = Equal.class),
|
@Spec(path = "amount", spec = Equal.class),
|
||||||
@Spec(path = "reference", spec = Equal.class),
|
@Spec(path = "reference", spec = Equal.class),
|
||||||
@Spec(path = "totalAmount", spec = Equal.class),
|
@Spec(path = "totalAmount", spec = Equal.class),
|
||||||
@Spec(path = "partyType", spec = Equal.class),
|
@Spec(path = "partyType", params = "partyType", paramSeparator = ',', spec = In.class),
|
||||||
@Spec(path = "sdkActionId", spec = Equal.class),
|
@Spec(path = "sdkActionId", spec = Equal.class),
|
||||||
@Spec(path = "paymentProcessorLabel", spec = Equal.class),
|
@Spec(path = "paymentProcessorLabel", spec = Equal.class),
|
||||||
})
|
})
|
||||||
}, and = {
|
}, and = {
|
||||||
@Spec(path = "type", spec = Equal.class),
|
@Spec(path = "type", spec = Equal.class),
|
||||||
@Spec(path = "userId", defaultVal = "null", spec = Equal.class),
|
@Spec(path = "workspaceId", defaultVal = "null", spec = Equal.class),
|
||||||
}) Specification<Transaction> specification, Pageable pageable) {
|
}) Specification<Transaction> specification, Pageable pageable) {
|
||||||
return ResponseEntity.ok(transactionService.findAll(specification, pageable));
|
return ResponseEntity.ok(transactionService.findAll(specification, pageable));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public ResponseEntity<Transaction> getById(@PathVariable UUID id) {
|
public ResponseEntity<Transaction> getById(
|
||||||
return ResponseEntity.ok(transactionService.findById(id));
|
@PathVariable UUID id,
|
||||||
|
@RequestParam UUID workspaceId) {
|
||||||
|
return ResponseEntity.ok(transactionService.getTransaction(id, workspaceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/integration/{id}")
|
@GetMapping("/integration/{id}")
|
||||||
@@ -192,8 +195,8 @@ public class TransactonController {
|
|||||||
|
|
||||||
var instance = workflowInstanceFactory.newWorkflowInstanceBuilder()
|
var instance = workflowInstanceFactory.newWorkflowInstanceBuilder()
|
||||||
.setType(TransactionWorkflow.TYPE)
|
.setType(TransactionWorkflow.TYPE)
|
||||||
.setExternalId(transaction.getUserId() + "-" + new Instant().getMillis())
|
.setExternalId(transaction.getWorkspaceId() + "-" + new Instant().getMillis())
|
||||||
.setBusinessKey(transaction.getUserId())
|
.setBusinessKey(transaction.getWorkspaceId().toString())
|
||||||
.putStateVariable("confirmation", Utils.toJson(transaction))
|
.putStateVariable("confirmation", Utils.toJson(transaction))
|
||||||
.setNextActivation(DateTime.now())
|
.setNextActivation(DateTime.now())
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package zw.qantra.tm.domain.controllers;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.kaczmarzyk.spring.data.jpa.domain.Equal;
|
||||||
|
import net.kaczmarzyk.spring.data.jpa.domain.EqualIgnoreCase;
|
||||||
|
import net.kaczmarzyk.spring.data.jpa.web.annotation.And;
|
||||||
|
import net.kaczmarzyk.spring.data.jpa.web.annotation.Join;
|
||||||
|
import net.kaczmarzyk.spring.data.jpa.web.annotation.Spec;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import zw.qantra.tm.domain.models.Workspace;
|
||||||
|
import zw.qantra.tm.domain.services.WorkspaceService;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/workspaces")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WorkspaceController {
|
||||||
|
|
||||||
|
private final WorkspaceService workspaceService;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity getAllWorkspaces(
|
||||||
|
@Join(path = "users", alias = "u")
|
||||||
|
@And({
|
||||||
|
@Spec(path = "name", spec = EqualIgnoreCase.class),
|
||||||
|
@Spec(path = "u.id", params = "userId", defaultVal = "null", spec = Equal.class)
|
||||||
|
}) Specification<Workspace> spec, Pageable pageable) {
|
||||||
|
return ResponseEntity.ok(workspaceService.getAllWorkspaces(spec, pageable));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ResponseEntity getWorkspace(@PathVariable UUID id) {
|
||||||
|
return workspaceService.getWorkspace(id)
|
||||||
|
.map(ResponseEntity::ok)
|
||||||
|
.orElse(ResponseEntity.notFound().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/search")
|
||||||
|
public ResponseEntity searchByName(@RequestParam String name) {
|
||||||
|
return ResponseEntity.ok(workspaceService.searchByName(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity createWorkspace(@RequestBody Workspace workspace) {
|
||||||
|
return ResponseEntity.ok(workspaceService.createWorkspace(workspace));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public ResponseEntity updateWorkspace(@PathVariable UUID id, @RequestBody Workspace workspace) {
|
||||||
|
Workspace updated = workspaceService.updateWorkspace(id, workspace);
|
||||||
|
if (updated != null) {
|
||||||
|
return ResponseEntity.ok(updated);
|
||||||
|
}
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ResponseEntity deleteWorkspace(@PathVariable UUID id) {
|
||||||
|
if (workspaceService.deleteWorkspace(id)) {
|
||||||
|
return ResponseEntity.ok(Map.of("message", "Workspace deleted successfully"));
|
||||||
|
}
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{workspaceId}/users/{userId}")
|
||||||
|
public ResponseEntity associateUser(@PathVariable UUID workspaceId, @PathVariable UUID userId) {
|
||||||
|
return workspaceService.associateUser(workspaceId, userId)
|
||||||
|
.map(ResponseEntity::ok)
|
||||||
|
.orElse(ResponseEntity.notFound().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{workspaceId}/users/{userId}")
|
||||||
|
public ResponseEntity disassociateUser(@PathVariable UUID workspaceId, @PathVariable UUID userId) {
|
||||||
|
return workspaceService.disassociateUser(workspaceId, userId)
|
||||||
|
.map(ResponseEntity::ok)
|
||||||
|
.orElse(ResponseEntity.notFound().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{workspaceId}/users")
|
||||||
|
public ResponseEntity getWorkspaceUsers(@PathVariable UUID workspaceId) {
|
||||||
|
return ResponseEntity.ok(workspaceService.getWorkspaceUsers(workspaceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/by-user/{userId}")
|
||||||
|
public ResponseEntity getUserWorkspaces(@PathVariable UUID userId) {
|
||||||
|
return ResponseEntity.ok(workspaceService.getUserWorkspaces(userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import java.util.UUID;
|
|||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
public class GroupBatchCreateRequest {
|
public class GroupBatchCreateRequest {
|
||||||
private UUID recipientGroupId;
|
private UUID recipientGroupId;
|
||||||
private String userId;
|
private UUID workspaceId;
|
||||||
private String description;
|
private String description;
|
||||||
private String requestedBy;
|
private String requestedBy;
|
||||||
private String currency;
|
private String currency;
|
||||||
|
|||||||
@@ -25,6 +25,6 @@ public class GroupBatchItemUpdateRequest {
|
|||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
public static class ListWrapper {
|
public static class ListWrapper {
|
||||||
private List<GroupBatchItemUpdateRequest> items;
|
private List<GroupBatchItemUpdateRequest> items;
|
||||||
private String userId;
|
private UUID workspaceId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,11 @@ package zw.qantra.tm.domain.dtos;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import zw.qantra.tm.domain.enums.AuthType;
|
import zw.qantra.tm.domain.enums.AuthType;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class GroupBatchTriggerRequest {
|
public class GroupBatchTriggerRequest {
|
||||||
private String userId;
|
private UUID workspaceId;
|
||||||
private String idempotencyKey;
|
private String idempotencyKey;
|
||||||
private AuthType authType;
|
private AuthType authType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import java.util.UUID;
|
|||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
public class GroupBatchUpdateRequest {
|
public class GroupBatchUpdateRequest {
|
||||||
private UUID id;
|
private UUID id;
|
||||||
private String userId;
|
private UUID workspaceId;
|
||||||
private String description;
|
private String description;
|
||||||
private String requestedBy;
|
private String requestedBy;
|
||||||
private String currency;
|
private String currency;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.util.UUID;
|
|||||||
@Data
|
@Data
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
public class GroupMemberRequest {
|
public class GroupMemberRequest {
|
||||||
private String userId;
|
private UUID workspaceId;
|
||||||
private List<UUID> recipientIds;
|
private List<UUID> recipientIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import lombok.Data;
|
|||||||
import zw.qantra.tm.domain.models.Recipient;
|
import zw.qantra.tm.domain.models.Recipient;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
@@ -12,6 +13,7 @@ public class RecipientGroupCreateRequest {
|
|||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
private String userId;
|
private String userId;
|
||||||
|
private UUID workspaceId;
|
||||||
private List<Recipient> recipients;
|
private List<Recipient> recipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ package zw.qantra.tm.domain.dtos;
|
|||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
public class RecipientGroupUpdateRequest {
|
public class RecipientGroupUpdateRequest {
|
||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
private String userId;
|
private UUID workspaceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "group_batch", indexes = {
|
@Table(name = "group_batch", indexes = {
|
||||||
@Index(name = "idx_group_batch_user_id", columnList = "user_id"),
|
@Index(name = "idx_group_batch_workspace_id", columnList = "workspace_id"),
|
||||||
@Index(name = "idx_group_batch_status", columnList = "status"),
|
@Index(name = "idx_group_batch_status", columnList = "status"),
|
||||||
@Index(name = "idx_group_batch_recipient_group_id", columnList = "recipient_group_id"),
|
@Index(name = "idx_group_batch_recipient_group_id", columnList = "recipient_group_id"),
|
||||||
@Index(name = "idx_group_batch_created_at", columnList = "created_at"),
|
@Index(name = "idx_group_batch_created_at", columnList = "created_at"),
|
||||||
@@ -32,6 +32,8 @@ import java.util.UUID;
|
|||||||
public class GroupBatch extends BaseEntity {
|
public class GroupBatch extends BaseEntity {
|
||||||
@Column(name = "recipient_group_id")
|
@Column(name = "recipient_group_id")
|
||||||
private UUID recipientGroupId;
|
private UUID recipientGroupId;
|
||||||
|
@Column(name = "workspace_id")
|
||||||
|
private UUID workspaceId;
|
||||||
@Column(name = "user_id")
|
@Column(name = "user_id")
|
||||||
private String userId;
|
private String userId;
|
||||||
private String description;
|
private String description;
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import jakarta.validation.constraints.NotNull;
|
|||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.hibernate.annotations.SQLRestriction;
|
import org.hibernate.annotations.SQLRestriction;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "recipient", indexes = {
|
@Table(name = "recipient", indexes = {
|
||||||
@Index(name = "idx_recipient_account_user", columnList = "account, user_id"),
|
@Index(name = "idx_recipient_account_workspace", columnList = "account, workspace_id"),
|
||||||
@Index(name = "idx_recipient_user_id", columnList = "user_id"),
|
@Index(name = "idx_recipient_workspace_id", columnList = "workspace_id"),
|
||||||
@Index(name = "idx_recipient_phone", columnList = "phone_number"),
|
@Index(name = "idx_recipient_phone", columnList = "phone_number"),
|
||||||
@Index(name = "idx_recipient_email", columnList = "email"),
|
@Index(name = "idx_recipient_email", columnList = "email"),
|
||||||
})
|
})
|
||||||
@@ -31,6 +33,8 @@ public class Recipient extends BaseEntity {
|
|||||||
private String initials;
|
private String initials;
|
||||||
@Column(name = "latest_provider_label")
|
@Column(name = "latest_provider_label")
|
||||||
private String latestProviderLabel;
|
private String latestProviderLabel;
|
||||||
|
@Column(name = "workspace_id")
|
||||||
|
private UUID workspaceId;
|
||||||
@Column(name = "user_id")
|
@Column(name = "user_id")
|
||||||
private String userId;
|
private String userId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import lombok.NoArgsConstructor;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.hibernate.annotations.SQLRestriction;
|
import org.hibernate.annotations.SQLRestriction;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "recipient_group", indexes = {
|
@Table(name = "recipient_group", indexes = {
|
||||||
@Index(name = "idx_recipient_group_user_id", columnList = "user_id"),
|
@Index(name = "idx_recipient_group_workspace_id", columnList = "workspace_id"),
|
||||||
})
|
})
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@@ -23,6 +25,8 @@ import org.hibernate.annotations.SQLRestriction;
|
|||||||
public class RecipientGroup extends BaseEntity {
|
public class RecipientGroup extends BaseEntity {
|
||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
|
@Column(name = "workspace_id")
|
||||||
|
private UUID workspaceId;
|
||||||
@Column(name = "user_id")
|
@Column(name = "user_id")
|
||||||
private String userId;
|
private String userId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ public class RecipientGroupMember extends BaseEntity {
|
|||||||
@Column(name = "recipient_uid")
|
@Column(name = "recipient_uid")
|
||||||
private UUID recipientUid;
|
private UUID recipientUid;
|
||||||
private String account;
|
private String account;
|
||||||
|
@Column(name = "workspace_id")
|
||||||
|
private UUID workspaceId;
|
||||||
@Column(name = "user_id")
|
@Column(name = "user_id")
|
||||||
private String userId;
|
private String userId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import java.util.UUID;
|
|||||||
@Table(name = "transaction", indexes = {
|
@Table(name = "transaction", indexes = {
|
||||||
@Index(name = "idx_transaction_trace_type", columnList = "trace, type"),
|
@Index(name = "idx_transaction_trace_type", columnList = "trace, type"),
|
||||||
@Index(name = "idx_transaction_reference", columnList = "reference"),
|
@Index(name = "idx_transaction_reference", columnList = "reference"),
|
||||||
@Index(name = "idx_transaction_user_id", columnList = "user_id"),
|
@Index(name = "idx_transaction_workspace_id", columnList = "workspace_id"),
|
||||||
@Index(name = "idx_transaction_confirm_pay_integ", columnList = "confirmation_status, payment_status, integration_status"),
|
@Index(name = "idx_transaction_confirm_pay_integ", columnList = "confirmation_status, payment_status, integration_status"),
|
||||||
@Index(name = "idx_transaction_pay_poll", columnList = "payment_status, polling_status"),
|
@Index(name = "idx_transaction_pay_poll", columnList = "payment_status, polling_status"),
|
||||||
@Index(name = "idx_transaction_status", columnList = "status"),
|
@Index(name = "idx_transaction_status", columnList = "status"),
|
||||||
@@ -33,6 +33,8 @@ import java.util.UUID;
|
|||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@SQLRestriction("deleted = false")
|
@SQLRestriction("deleted = false")
|
||||||
public class Transaction extends BaseEntity {
|
public class Transaction extends BaseEntity {
|
||||||
|
@Column(name = "workspace_id")
|
||||||
|
private UUID workspaceId;
|
||||||
@Column(name = "user_id")
|
@Column(name = "user_id")
|
||||||
private String userId;
|
private String userId;
|
||||||
private String trace;
|
private String trace;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package zw.qantra.tm.domain.models;
|
package zw.qantra.tm.domain.models;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@@ -9,7 +10,9 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "users", indexes = {
|
@Table(name = "users", indexes = {
|
||||||
@@ -50,6 +53,10 @@ public class User extends BaseEntity implements UserDetails {
|
|||||||
|
|
||||||
@Column(name = "is_credentials_non_expired")
|
@Column(name = "is_credentials_non_expired")
|
||||||
private boolean credentialsNonExpired = true;
|
private boolean credentialsNonExpired = true;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@ManyToMany(mappedBy = "users", fetch = FetchType.LAZY)
|
||||||
|
private Set<Workspace> workspaces = new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
|||||||
39
src/main/java/zw/qantra/tm/domain/models/Workspace.java
Normal file
39
src/main/java/zw/qantra/tm/domain/models/Workspace.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package zw.qantra.tm.domain.models;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.hibernate.annotations.SQLRestriction;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "workspace", indexes = {
|
||||||
|
@Index(name = "idx_workspace_name", columnList = "name"),
|
||||||
|
})
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@SQLRestriction("deleted = false")
|
||||||
|
public class Workspace extends BaseEntity {
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
private String phone;
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@ManyToMany(fetch = FetchType.LAZY)
|
||||||
|
@JoinTable(
|
||||||
|
name = "workspace_users",
|
||||||
|
joinColumns = @JoinColumn(name = "workspace_id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "user_id")
|
||||||
|
)
|
||||||
|
@Builder.Default
|
||||||
|
private Set<User> users = new HashSet<>();
|
||||||
|
}
|
||||||
@@ -5,11 +5,13 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
|||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import zw.qantra.tm.domain.models.GroupBatch;
|
import zw.qantra.tm.domain.models.GroupBatch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface GroupBatchRepository extends JpaRepository<GroupBatch, UUID>, JpaSpecificationExecutor<GroupBatch> {
|
public interface GroupBatchRepository extends JpaRepository<GroupBatch, UUID>, JpaSpecificationExecutor<GroupBatch> {
|
||||||
Optional<GroupBatch> findByIdAndUserId(UUID id, String userId);
|
Optional<GroupBatch> findByIdAndWorkspaceId(UUID id, UUID workspaceId);
|
||||||
|
List<GroupBatch> findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ public interface RecipientGroupMemberRepository extends JpaRepository<RecipientG
|
|||||||
List<RecipientGroupMember> findAllByRecipientGroupId(UUID recipientGroupId);
|
List<RecipientGroupMember> findAllByRecipientGroupId(UUID recipientGroupId);
|
||||||
boolean existsByRecipientGroupIdAndRecipientId(UUID recipientGroupId, UUID recipientId);
|
boolean existsByRecipientGroupIdAndRecipientId(UUID recipientGroupId, UUID recipientId);
|
||||||
void deleteAllByRecipientGroupId(UUID recipientGroupId);
|
void deleteAllByRecipientGroupId(UUID recipientGroupId);
|
||||||
|
List<RecipientGroupMember> findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import java.util.UUID;
|
|||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface RecipientGroupRepository extends JpaRepository<RecipientGroup, UUID>, JpaSpecificationExecutor<RecipientGroup> {
|
public interface RecipientGroupRepository extends JpaRepository<RecipientGroup, UUID>, JpaSpecificationExecutor<RecipientGroup> {
|
||||||
List<RecipientGroup> findAllByUserId(String userId);
|
List<RecipientGroup> findAllByWorkspaceId(UUID workspaceId);
|
||||||
Optional<RecipientGroup> findByIdAndUserId(UUID id, String userId);
|
Optional<RecipientGroup> findByIdAndWorkspaceId(UUID id, UUID workspaceId);
|
||||||
|
List<RecipientGroup> findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ public interface RecipientRepository extends JpaRepository<Recipient, UUID>, Jpa
|
|||||||
List<Recipient> findByNameContainingIgnoreCase(String name);
|
List<Recipient> findByNameContainingIgnoreCase(String name);
|
||||||
List<Recipient> findByEmailContainingIgnoreCase(String email);
|
List<Recipient> findByEmailContainingIgnoreCase(String email);
|
||||||
List<Recipient> findByPhoneNumberContaining(String phoneNumber);
|
List<Recipient> findByPhoneNumberContaining(String phoneNumber);
|
||||||
List<Recipient> findByAccountAndUserId(String account, String userId);
|
List<Recipient> findByAccountAndWorkspaceId(String account, UUID workspaceId);
|
||||||
}
|
List<Recipient> findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ import java.util.UUID;
|
|||||||
public interface TransactionRepository extends JpaRepository<Transaction, UUID>, JpaSpecificationExecutor<Transaction> {
|
public interface TransactionRepository extends JpaRepository<Transaction, UUID>, JpaSpecificationExecutor<Transaction> {
|
||||||
Transaction findByTraceAndType(String trace, RequestType type);
|
Transaction findByTraceAndType(String trace, RequestType type);
|
||||||
Optional<Transaction> findByReference(String reference);
|
Optional<Transaction> findByReference(String reference);
|
||||||
List<Transaction> findAllByUserId(String uid);
|
List<Transaction> findAllByUserId(String userId);
|
||||||
|
Optional<Transaction> findByIdAndWorkspaceId(UUID id, UUID workspaceId);
|
||||||
|
List<Transaction> findAllByWorkspaceId(UUID workspaceId);
|
||||||
|
List<Transaction> findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
List<Transaction> findAllByConfirmationStatusAndPaymentStatusAndIntegrationStatus(
|
List<Transaction> findAllByConfirmationStatusAndPaymentStatusAndIntegrationStatus(
|
||||||
Status s1, Status s2, Status s3);
|
Status s1, Status s2, Status s3);
|
||||||
List<Transaction> findAllByPaymentStatusAndPollingStatus(Status s1, Status s2);
|
List<Transaction> findAllByPaymentStatusAndPollingStatus(Status s1, Status s2);
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package zw.qantra.tm.domain.repositories;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import zw.qantra.tm.domain.models.Workspace;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface WorkspaceRepository extends JpaRepository<Workspace, UUID>, JpaSpecificationExecutor<Workspace> {
|
||||||
|
List<Workspace> findByNameContainingIgnoreCase(String name);
|
||||||
|
}
|
||||||
@@ -52,8 +52,8 @@ public class BatchReportService {
|
|||||||
private final GroupBatchItemRepository groupBatchItemRepository;
|
private final GroupBatchItemRepository groupBatchItemRepository;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public BatchReportResult generateBatchReport(UUID batchId, String userId) {
|
public BatchReportResult generateBatchReport(UUID batchId, UUID workspaceId) {
|
||||||
GroupBatch batch = groupBatchRepository.findByIdAndUserId(batchId, userId)
|
GroupBatch batch = groupBatchRepository.findByIdAndWorkspaceId(batchId, workspaceId)
|
||||||
.orElseThrow(() -> new ApiException("Group batch not found"));
|
.orElseThrow(() -> new ApiException("Group batch not found"));
|
||||||
|
|
||||||
if (!REPORTABLE_STATUSES.contains(batch.getStatus())) {
|
if (!REPORTABLE_STATUSES.contains(batch.getStatus())) {
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ public class GroupBatchService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public GroupBatch createBatch(GroupBatchCreateRequest request) {
|
public GroupBatch createBatch(GroupBatchCreateRequest request) {
|
||||||
RecipientGroup group = recipientGroupService.get(
|
RecipientGroup group = recipientGroupService.get(
|
||||||
request.getRecipientGroupId(), request.getUserId());
|
request.getRecipientGroupId(), request.getWorkspaceId());
|
||||||
|
|
||||||
List<RecipientGroupMember> members = recipientGroupService.members(
|
List<RecipientGroupMember> members = recipientGroupService.members(
|
||||||
group.getId(), request.getUserId());
|
group.getId(), request.getWorkspaceId());
|
||||||
|
|
||||||
if (members.isEmpty()) {
|
if (members.isEmpty()) {
|
||||||
throw new ApiException("Recipient group has no members");
|
throw new ApiException("Recipient group has no members");
|
||||||
@@ -78,7 +78,7 @@ public class GroupBatchService {
|
|||||||
|
|
||||||
GroupBatch batch = GroupBatch.builder()
|
GroupBatch batch = GroupBatch.builder()
|
||||||
.recipientGroupId(group.getId())
|
.recipientGroupId(group.getId())
|
||||||
.userId(request.getUserId())
|
.workspaceId(request.getWorkspaceId())
|
||||||
.description(request.getDescription())
|
.description(request.getDescription())
|
||||||
.requestedBy(request.getRequestedBy())
|
.requestedBy(request.getRequestedBy())
|
||||||
.currency(request.getCurrency())
|
.currency(request.getCurrency())
|
||||||
@@ -126,8 +126,8 @@ public class GroupBatchService {
|
|||||||
return groupBatchRepository.save(savedBatch);
|
return groupBatchRepository.save(savedBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupBatch triggerConfirm(UUID batchId, String userId, String idempotencyKey) {
|
public GroupBatch triggerConfirm(UUID batchId, UUID workspaceId, String idempotencyKey) {
|
||||||
GroupBatch batch = getBatch(batchId, userId);
|
GroupBatch batch = getBatch(batchId, workspaceId);
|
||||||
|
|
||||||
if (batch.getConfirmIdempotencyKey() != null && batch.getConfirmIdempotencyKey().equals(idempotencyKey)) {
|
if (batch.getConfirmIdempotencyKey() != null && batch.getConfirmIdempotencyKey().equals(idempotencyKey)) {
|
||||||
return batch;
|
return batch;
|
||||||
@@ -140,7 +140,7 @@ public class GroupBatchService {
|
|||||||
if (batch.getWorkflowId() == null) {
|
if (batch.getWorkflowId() == null) {
|
||||||
var instance = workflowInstanceFactory.newWorkflowInstanceBuilder()
|
var instance = workflowInstanceFactory.newWorkflowInstanceBuilder()
|
||||||
.setType(BatchWorkflow.TYPE)
|
.setType(BatchWorkflow.TYPE)
|
||||||
.setExternalId(batch.getUserId() + "-batch-" + new Instant().getMillis())
|
.setExternalId(batch.getWorkspaceId() + "-batch-" + new Instant().getMillis())
|
||||||
.setBusinessKey(batch.getId().toString())
|
.setBusinessKey(batch.getId().toString())
|
||||||
.putStateVariable("batchId", Utils.toJson(batch.getId().toString()))
|
.putStateVariable("batchId", Utils.toJson(batch.getId().toString()))
|
||||||
.setNextActivation(DateTime.now())
|
.setNextActivation(DateTime.now())
|
||||||
@@ -170,9 +170,9 @@ public class GroupBatchService {
|
|||||||
return batch;
|
return batch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object triggerRequest(UUID batchId, String userId,
|
public Object triggerRequest(UUID batchId, UUID workspaceId,
|
||||||
AuthType authType, String idempotencyKey) {
|
AuthType authType, String idempotencyKey) {
|
||||||
GroupBatch batch = getBatch(batchId, userId);
|
GroupBatch batch = getBatch(batchId, workspaceId);
|
||||||
|
|
||||||
if (batch.getRequestIdempotencyKey() != null && batch.getRequestIdempotencyKey().equals(idempotencyKey)) {
|
if (batch.getRequestIdempotencyKey() != null && batch.getRequestIdempotencyKey().equals(idempotencyKey)) {
|
||||||
return batch;
|
return batch;
|
||||||
@@ -217,8 +217,8 @@ public class GroupBatchService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object triggerPoll(UUID batchId, String userId, String idempotencyKey) {
|
public Object triggerPoll(UUID batchId, UUID workspaceId, String idempotencyKey) {
|
||||||
GroupBatch batch = getBatch(batchId, userId);
|
GroupBatch batch = getBatch(batchId, workspaceId);
|
||||||
|
|
||||||
if (batch.getPollIdempotencyKey() != null && batch.getPollIdempotencyKey().equals(idempotencyKey)) {
|
if (batch.getPollIdempotencyKey() != null && batch.getPollIdempotencyKey().equals(idempotencyKey)) {
|
||||||
return batch;
|
return batch;
|
||||||
@@ -284,8 +284,8 @@ public class GroupBatchService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupBatch getBatch(UUID batchId, String userId) {
|
public GroupBatch getBatch(UUID batchId, UUID workspaceId) {
|
||||||
return groupBatchRepository.findByIdAndUserId(batchId, userId)
|
return groupBatchRepository.findByIdAndWorkspaceId(batchId, workspaceId)
|
||||||
.orElseThrow(() -> new ApiException("Group batch not found"));
|
.orElseThrow(() -> new ApiException("Group batch not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ public class GroupBatchService {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public GroupBatch updateBatch(GroupBatchUpdateRequest request) {
|
public GroupBatch updateBatch(GroupBatchUpdateRequest request) {
|
||||||
GroupBatch batch = getBatch(request.getId(), request.getUserId());
|
GroupBatch batch = getBatch(request.getId(), request.getWorkspaceId());
|
||||||
|
|
||||||
if (!UPDATABLE_STATUSES.contains(batch.getStatus())) {
|
if (!UPDATABLE_STATUSES.contains(batch.getStatus())) {
|
||||||
throw new ApiException(
|
throw new ApiException(
|
||||||
@@ -350,9 +350,9 @@ public class GroupBatchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public List<GroupBatchItem> updateBatchItems(UUID batchId, String userId,
|
public List<GroupBatchItem> updateBatchItems(UUID batchId, UUID workspaceId,
|
||||||
List<GroupBatchItemUpdateRequest> items) {
|
List<GroupBatchItemUpdateRequest> items) {
|
||||||
GroupBatch batch = getBatch(batchId, userId);
|
GroupBatch batch = getBatch(batchId, workspaceId);
|
||||||
|
|
||||||
if (!UPDATABLE_STATUSES.contains(batch.getStatus())) {
|
if (!UPDATABLE_STATUSES.contains(batch.getStatus())) {
|
||||||
throw new ApiException(
|
throw new ApiException(
|
||||||
@@ -424,8 +424,8 @@ public class GroupBatchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deleteBatch(UUID batchId, String userId) {
|
public void deleteBatch(UUID batchId, UUID workspaceId) {
|
||||||
GroupBatch batch = getBatch(batchId, userId);
|
GroupBatch batch = getBatch(batchId, workspaceId);
|
||||||
|
|
||||||
if (!DELETABLE_STATUSES.contains(batch.getStatus())) {
|
if (!DELETABLE_STATUSES.contains(batch.getStatus())) {
|
||||||
throw new ApiException(
|
throw new ApiException(
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ public class GroupBatchWorkflowService {
|
|||||||
BigDecimal total = confirmedItems.stream()
|
BigDecimal total = confirmedItems.stream()
|
||||||
.map(item -> item.getAmount() == null ? BigDecimal.ZERO : item.getAmount())
|
.map(item -> item.getAmount() == null ? BigDecimal.ZERO : item.getAmount())
|
||||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
User user = userService.getUserRepository().findById(UUID.fromString(batch.getUserId())).orElseThrow();
|
User user = userService.getUserRepository().findByUsername(SecurityUtils.getCurrentUsername()).orElseThrow();
|
||||||
|
|
||||||
Transaction transaction = new Transaction();
|
Transaction transaction = new Transaction();
|
||||||
transaction.setId(null);
|
transaction.setId(null);
|
||||||
@@ -113,7 +113,7 @@ public class GroupBatchWorkflowService {
|
|||||||
transaction.setAmount(total);
|
transaction.setAmount(total);
|
||||||
transaction.setTotalAmount(total);
|
transaction.setTotalAmount(total);
|
||||||
transaction.setReference("batch-" + batch.getId());
|
transaction.setReference("batch-" + batch.getId());
|
||||||
transaction.setUserId(batch.getUserId());
|
transaction.setWorkspaceId(batch.getWorkspaceId());
|
||||||
transaction.setPaymentProcessorLabel(batch.getPaymentProcessorLabel());
|
transaction.setPaymentProcessorLabel(batch.getPaymentProcessorLabel());
|
||||||
transaction.setPaymentProcessorName(batch.getPaymentProcessorName());
|
transaction.setPaymentProcessorName(batch.getPaymentProcessorName());
|
||||||
transaction.setPaymentProcessorImage(batch.getPaymentProcessorImage());
|
transaction.setPaymentProcessorImage(batch.getPaymentProcessorImage());
|
||||||
@@ -205,7 +205,7 @@ public class GroupBatchWorkflowService {
|
|||||||
private void confirmItem(GroupBatch batch, GroupBatchItem item) {
|
private void confirmItem(GroupBatch batch, GroupBatchItem item) {
|
||||||
GroupBatchItem mutableItem = groupBatchItemRepository.findById(item.getId()).orElse(item);
|
GroupBatchItem mutableItem = groupBatchItemRepository.findById(item.getId()).orElse(item);
|
||||||
try {
|
try {
|
||||||
User user = userService.getUserRepository().findById(UUID.fromString(batch.getUserId())).orElseThrow();
|
User user = userService.getUserRepository().findByUsername(SecurityUtils.getCurrentUsername()).orElseThrow();
|
||||||
Transaction transaction = new Transaction();
|
Transaction transaction = new Transaction();
|
||||||
transaction.setId(null);
|
transaction.setId(null);
|
||||||
transaction.setDebitPhone(user.getPhone());
|
transaction.setDebitPhone(user.getPhone());
|
||||||
@@ -219,7 +219,7 @@ public class GroupBatchWorkflowService {
|
|||||||
transaction.setProviderImage(item.getProviderImage());
|
transaction.setProviderImage(item.getProviderImage());
|
||||||
transaction.setProviderLabel(item.getProviderLabel());
|
transaction.setProviderLabel(item.getProviderLabel());
|
||||||
|
|
||||||
transaction.setUserId(batch.getUserId());
|
transaction.setWorkspaceId(batch.getWorkspaceId());
|
||||||
transaction.setType(RequestType.CONFIRM);
|
transaction.setType(RequestType.CONFIRM);
|
||||||
transaction.setPartyType(PartyType.BATCH);
|
transaction.setPartyType(PartyType.BATCH);
|
||||||
transaction.setAuthType(AuthType.REMOTE); // default to remote for now
|
transaction.setAuthType(AuthType.REMOTE); // default to remote for now
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class RecipientGroupService {
|
|||||||
* 5. Return the batch + any row-level errors
|
* 5. Return the batch + any row-level errors
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public GroupCreateFromFileResult createFromFile(MultipartFile file, GroupCreateFromFileRequest request, String userId) {
|
public GroupCreateFromFileResult createFromFile(MultipartFile file, GroupCreateFromFileRequest request, UUID workspaceId) {
|
||||||
ParseResult parseResult = parseCsv(file);
|
ParseResult parseResult = parseCsv(file);
|
||||||
|
|
||||||
if(!parseResult.parseErrors.isEmpty()) {
|
if(!parseResult.parseErrors.isEmpty()) {
|
||||||
@@ -77,7 +77,7 @@ public class RecipientGroupService {
|
|||||||
.name(row.name)
|
.name(row.name)
|
||||||
.account(row.account)
|
.account(row.account)
|
||||||
.phoneNumber(row.phone)
|
.phoneNumber(row.phone)
|
||||||
.userId(userId)
|
.workspaceId(workspaceId)
|
||||||
.build();
|
.build();
|
||||||
recipients.add(recipient);
|
recipients.add(recipient);
|
||||||
}
|
}
|
||||||
@@ -86,15 +86,15 @@ public class RecipientGroupService {
|
|||||||
RecipientGroup group = RecipientGroup.builder()
|
RecipientGroup group = RecipientGroup.builder()
|
||||||
.name(request.getGroupName())
|
.name(request.getGroupName())
|
||||||
.description(request.getDescription())
|
.description(request.getDescription())
|
||||||
.userId(userId)
|
.workspaceId(workspaceId)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
RecipientGroup savedGroup = recipientGroupRepository.save(group);
|
RecipientGroup savedGroup = recipientGroupRepository.save(group);
|
||||||
|
|
||||||
List<RecipientGroupMember> members = addMembers(savedGroup.getId(), userId, recipients);
|
List<RecipientGroupMember> members = addMembers(savedGroup.getId(), workspaceId, recipients);
|
||||||
|
|
||||||
// Step 3: create group batch (inline to avoid circular dependency with GroupBatchService)
|
// Step 3: create group batch (inline to avoid circular dependency with GroupBatchService)
|
||||||
GroupBatch batch = createBatchInline(savedGroup.getId(), userId, request, members);
|
GroupBatch batch = createBatchInline(savedGroup.getId(), workspaceId, request, members);
|
||||||
|
|
||||||
// Step 4: update batch items with bill/provider fields from CSV
|
// Step 4: update batch items with bill/provider fields from CSV
|
||||||
List<GroupBatchItem> batchItems = groupBatchItemRepository.findAllByGroupBatchId(batch.getId());
|
List<GroupBatchItem> batchItems = groupBatchItemRepository.findAllByGroupBatchId(batch.getId());
|
||||||
@@ -136,7 +136,7 @@ public class RecipientGroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the updated batch + errors
|
// Return the updated batch + errors
|
||||||
GroupBatch resultBatch = groupBatchRepository.findByIdAndUserId(batch.getId(), userId)
|
GroupBatch resultBatch = groupBatchRepository.findByIdAndWorkspaceId(batch.getId(), workspaceId)
|
||||||
.orElseThrow(() -> new ApiException("Batch not found after creation"));
|
.orElseThrow(() -> new ApiException("Batch not found after creation"));
|
||||||
|
|
||||||
return GroupCreateFromFileResult.builder()
|
return GroupCreateFromFileResult.builder()
|
||||||
@@ -152,12 +152,12 @@ public class RecipientGroupService {
|
|||||||
* Create a GroupBatch and its items directly (mirrors GroupBatchService.createBatch logic
|
* Create a GroupBatch and its items directly (mirrors GroupBatchService.createBatch logic
|
||||||
* but without circular dependency).
|
* but without circular dependency).
|
||||||
*/
|
*/
|
||||||
private GroupBatch createBatchInline(UUID recipientGroupId, String userId,
|
private GroupBatch createBatchInline(UUID recipientGroupId, UUID workspaceId,
|
||||||
GroupCreateFromFileRequest request,
|
GroupCreateFromFileRequest request,
|
||||||
List<RecipientGroupMember> members) {
|
List<RecipientGroupMember> members) {
|
||||||
GroupBatch batch = GroupBatch.builder()
|
GroupBatch batch = GroupBatch.builder()
|
||||||
.recipientGroupId(recipientGroupId)
|
.recipientGroupId(recipientGroupId)
|
||||||
.userId(userId)
|
.workspaceId(workspaceId)
|
||||||
.description(request.getDescription())
|
.description(request.getDescription())
|
||||||
.requestedBy(request.getRequestedBy())
|
.requestedBy(request.getRequestedBy())
|
||||||
.currency(request.getCurrency())
|
.currency(request.getCurrency())
|
||||||
@@ -384,25 +384,26 @@ public class RecipientGroupService {
|
|||||||
RecipientGroup savedGroup = recipientGroupRepository.save(group);
|
RecipientGroup savedGroup = recipientGroupRepository.save(group);
|
||||||
|
|
||||||
if (recipients != null && !recipients.isEmpty()) {
|
if (recipients != null && !recipients.isEmpty()) {
|
||||||
addMembers(savedGroup.getId(), savedGroup.getUserId(), recipients);
|
addMembers(savedGroup.getId(), savedGroup.getWorkspaceId(), recipients);
|
||||||
}
|
}
|
||||||
|
|
||||||
return savedGroup;
|
return savedGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public List<RecipientGroupMember> addMembers(UUID groupId, String userId, List<Recipient> recipients) {
|
public List<RecipientGroupMember> addMembers(UUID groupId, UUID workspaceId, List<Recipient> recipients) {
|
||||||
get(groupId, userId);
|
get(groupId, workspaceId);
|
||||||
List<RecipientGroupMember> added = new ArrayList<>();
|
List<RecipientGroupMember> added = new ArrayList<>();
|
||||||
for (Recipient incomingRecipient : recipients) {
|
for (Recipient incomingRecipient : recipients) {
|
||||||
Recipient recipient = resolveOrCreateRecipient(incomingRecipient, userId);
|
Recipient recipient = resolveOrCreateRecipient(incomingRecipient, workspaceId);
|
||||||
|
|
||||||
RecipientGroupMember member = RecipientGroupMember.builder()
|
RecipientGroupMember member = RecipientGroupMember.builder()
|
||||||
.recipientGroupId(groupId)
|
.recipientGroupId(groupId)
|
||||||
.recipientUid(recipient.getId())
|
.recipientUid(recipient.getId())
|
||||||
.recipient(recipient)
|
.recipient(recipient)
|
||||||
.account(recipient.getAccount())
|
.account(recipient.getAccount())
|
||||||
.userId(userId)
|
.workspaceId(workspaceId)
|
||||||
|
.userId(incomingRecipient.getUserId())
|
||||||
.build();
|
.build();
|
||||||
added.add(recipientGroupMemberRepository.save(member));
|
added.add(recipientGroupMemberRepository.save(member));
|
||||||
}
|
}
|
||||||
@@ -413,25 +414,25 @@ public class RecipientGroupService {
|
|||||||
return recipientGroupRepository.findAll(spec, pageable);
|
return recipientGroupRepository.findAll(spec, pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RecipientGroup> list(String userId) {
|
public List<RecipientGroup> list(UUID workspaceId) {
|
||||||
return recipientGroupRepository.findAllByUserId(userId);
|
return recipientGroupRepository.findAllByWorkspaceId(workspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecipientGroup get(UUID groupId, String userId) {
|
public RecipientGroup get(UUID groupId, UUID workspaceId) {
|
||||||
return recipientGroupRepository.findByIdAndUserId(groupId, userId)
|
return recipientGroupRepository.findByIdAndWorkspaceId(groupId, workspaceId)
|
||||||
.orElseThrow(() -> new ApiException("Recipient group not found"));
|
.orElseThrow(() -> new ApiException("Recipient group not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecipientGroup update(UUID groupId, String userId, String name, String description) {
|
public RecipientGroup update(UUID groupId, UUID workspaceId, String name, String description) {
|
||||||
RecipientGroup group = get(groupId, userId);
|
RecipientGroup group = get(groupId, workspaceId);
|
||||||
group.setName(name);
|
group.setName(name);
|
||||||
group.setDescription(description);
|
group.setDescription(description);
|
||||||
return recipientGroupRepository.save(group);
|
return recipientGroupRepository.save(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void delete(UUID groupId, String userId) {
|
public void delete(UUID groupId, UUID workspaceId) {
|
||||||
RecipientGroup group = get(groupId, userId);
|
RecipientGroup group = get(groupId, workspaceId);
|
||||||
group.setDeleted(true);
|
group.setDeleted(true);
|
||||||
recipientGroupRepository.save(group);
|
recipientGroupRepository.save(group);
|
||||||
|
|
||||||
@@ -441,14 +442,14 @@ public class RecipientGroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public List<RecipientGroupMember> addMembersByIds(UUID groupId, String userId, List<UUID> recipientIds) {
|
public List<RecipientGroupMember> addMembersByIds(UUID groupId, UUID workspaceId, List<UUID> recipientIds) {
|
||||||
get(groupId, userId);
|
get(groupId, workspaceId);
|
||||||
List<RecipientGroupMember> added = new ArrayList<>();
|
List<RecipientGroupMember> added = new ArrayList<>();
|
||||||
for (UUID recipientId : recipientIds) {
|
for (UUID recipientId : recipientIds) {
|
||||||
Recipient recipient = recipientRepository.findById(recipientId)
|
Recipient recipient = recipientRepository.findById(recipientId)
|
||||||
.orElseThrow(() -> new ApiException("Recipient not found: " + recipientId));
|
.orElseThrow(() -> new ApiException("Recipient not found: " + recipientId));
|
||||||
if (!userId.equals(recipient.getUserId())) {
|
if (!workspaceId.equals(recipient.getWorkspaceId())) {
|
||||||
throw new ApiException("Recipient does not belong to user");
|
throw new ApiException("Recipient does not belong to workspace");
|
||||||
}
|
}
|
||||||
if (recipientGroupMemberRepository.existsByRecipientGroupIdAndRecipientId(groupId, recipientId)) {
|
if (recipientGroupMemberRepository.existsByRecipientGroupIdAndRecipientId(groupId, recipientId)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -458,23 +459,23 @@ public class RecipientGroupService {
|
|||||||
.recipientUid(recipientId)
|
.recipientUid(recipientId)
|
||||||
.recipient(recipient)
|
.recipient(recipient)
|
||||||
.account(recipient.getAccount())
|
.account(recipient.getAccount())
|
||||||
.userId(userId)
|
.workspaceId(workspaceId)
|
||||||
.build();
|
.build();
|
||||||
added.add(recipientGroupMemberRepository.save(member));
|
added.add(recipientGroupMemberRepository.save(member));
|
||||||
}
|
}
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Recipient resolveOrCreateRecipient(Recipient incomingRecipient, String fallbackUserId) {
|
private Recipient resolveOrCreateRecipient(Recipient incomingRecipient, UUID fallbackWorkspaceId) {
|
||||||
if (incomingRecipient == null || incomingRecipient.getAccount() == null || incomingRecipient.getAccount().isBlank()) {
|
if (incomingRecipient == null || incomingRecipient.getAccount() == null || incomingRecipient.getAccount().isBlank()) {
|
||||||
throw new ApiException("Recipient account is required");
|
throw new ApiException("Recipient account is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
String recipientUserId = incomingRecipient.getUserId() == null || incomingRecipient.getUserId().isBlank()
|
UUID recipientWorkspaceId = incomingRecipient.getWorkspaceId() == null
|
||||||
? fallbackUserId
|
? fallbackWorkspaceId
|
||||||
: incomingRecipient.getUserId();
|
: incomingRecipient.getWorkspaceId();
|
||||||
|
|
||||||
List<Recipient> existing = recipientRepository.findByAccountAndUserId(incomingRecipient.getAccount(), recipientUserId);
|
List<Recipient> existing = recipientRepository.findByAccountAndWorkspaceId(incomingRecipient.getAccount(), recipientWorkspaceId);
|
||||||
if (!existing.isEmpty()) {
|
if (!existing.isEmpty()) {
|
||||||
Recipient recipient = existing.get(0);
|
Recipient recipient = existing.get(0);
|
||||||
recipient.setName(incomingRecipient.getName());
|
recipient.setName(incomingRecipient.getName());
|
||||||
@@ -483,13 +484,13 @@ public class RecipientGroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
incomingRecipient.setId(null);
|
incomingRecipient.setId(null);
|
||||||
incomingRecipient.setUserId(recipientUserId);
|
incomingRecipient.setWorkspaceId(recipientWorkspaceId);
|
||||||
return recipientRepository.save(incomingRecipient);
|
return recipientRepository.save(incomingRecipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void removeMember(UUID groupId, UUID recipientId, String userId) {
|
public void removeMember(UUID groupId, UUID recipientId, UUID workspaceId) {
|
||||||
get(groupId, userId);
|
get(groupId, workspaceId);
|
||||||
List<RecipientGroupMember> members = recipientGroupMemberRepository.findAllByRecipientGroupId(groupId);
|
List<RecipientGroupMember> members = recipientGroupMemberRepository.findAllByRecipientGroupId(groupId);
|
||||||
RecipientGroupMember target = members.stream()
|
RecipientGroupMember target = members.stream()
|
||||||
.filter(item -> recipientId.equals(item.getRecipientUid()))
|
.filter(item -> recipientId.equals(item.getRecipientUid()))
|
||||||
@@ -499,8 +500,8 @@ public class RecipientGroupService {
|
|||||||
recipientGroupMemberRepository.save(target);
|
recipientGroupMemberRepository.save(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RecipientGroupMember> members(UUID groupId, String userId) {
|
public List<RecipientGroupMember> members(UUID groupId, UUID workspaceId) {
|
||||||
get(groupId, userId);
|
get(groupId, workspaceId);
|
||||||
return recipientGroupMemberRepository.findAllByRecipientGroupId(groupId);
|
return recipientGroupMemberRepository.findAllByRecipientGroupId(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package zw.qantra.tm.domain.services;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import zw.qantra.tm.domain.models.Recipient;
|
import zw.qantra.tm.domain.models.Recipient;
|
||||||
import zw.qantra.tm.domain.repositories.RecipientRepository;
|
import zw.qantra.tm.domain.repositories.RecipientRepository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -21,8 +22,8 @@ public class RecipientService {
|
|||||||
return recipientRepository.findAll();
|
return recipientRepository.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Recipient> getRecipient(String account, String userId) {
|
public List<Recipient> getRecipient(String account, UUID workspaceId) {
|
||||||
return recipientRepository.findByAccountAndUserId(account, userId);
|
return recipientRepository.findByAccountAndWorkspaceId(account, workspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Recipient save(Recipient recipient) {
|
public Recipient save(Recipient recipient) {
|
||||||
@@ -45,7 +46,7 @@ public class RecipientService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Recipient> searchRecipients(Specification<Recipient> specification) {
|
public Page<Recipient> findAllRecipients(Specification<Recipient> specification, Pageable pageable) {
|
||||||
return recipientRepository.findAll(specification);
|
return recipientRepository.findAll(specification, pageable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,16 +47,30 @@ public class TransactionService {
|
|||||||
return creditAmount;
|
return creditAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reassignTransactions(String oldUid, String newUid){
|
public void reassignTransactions(UUID oldWorkspaceId, UUID newWorkspaceId){
|
||||||
List<Transaction> transactions = transactionRepository.findAllByUserId(oldUid);
|
List<Transaction> transactions = transactionRepository.findAllByWorkspaceId(oldWorkspaceId);
|
||||||
transactions.forEach(transaction -> {
|
transactions.forEach(transaction -> {
|
||||||
transaction.setUserId(newUid);
|
transaction.setWorkspaceId(newWorkspaceId);
|
||||||
transactionRepository.save(transaction);
|
transactionRepository.save(transaction);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reassignTransactions(String oldUserId, String newUserId){
|
||||||
|
List<Transaction> transactions = transactionRepository.findAllByUserId(oldUserId);
|
||||||
|
transactions.forEach(transaction -> {
|
||||||
|
transaction.setUserId(newUserId);
|
||||||
|
transactionRepository.save(transaction);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transaction getTransaction(UUID id, UUID workspaceId) {
|
||||||
|
return transactionRepository.findByIdAndWorkspaceId(id, workspaceId)
|
||||||
|
.orElseThrow(() -> new ApiException("Transaction not found"));
|
||||||
|
}
|
||||||
|
|
||||||
public Transaction findById(UUID id) {
|
public Transaction findById(UUID id) {
|
||||||
Transaction transaction = transactionRepository.findById(id).orElseThrow(() -> new ApiException("Transaction not found for ID: " + id));
|
Transaction transaction = transactionRepository.findById(id).orElseThrow(() ->
|
||||||
|
new ApiException("Transaction not found for ID: " + id));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AdditionalData additionalData = additionalDataService.getAdditionalDataRepository()
|
AdditionalData additionalData = additionalDataService.getAdditionalDataRepository()
|
||||||
|
|||||||
@@ -0,0 +1,203 @@
|
|||||||
|
package zw.qantra.tm.domain.services;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import zw.qantra.tm.domain.models.*;
|
||||||
|
import zw.qantra.tm.domain.repositories.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WorkspaceMigrationService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(WorkspaceMigrationService.class);
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final WorkspaceRepository workspaceRepository;
|
||||||
|
private final TransactionRepository transactionRepository;
|
||||||
|
private final RecipientRepository recipientRepository;
|
||||||
|
private final RecipientGroupRepository recipientGroupRepository;
|
||||||
|
private final RecipientGroupMemberRepository recipientGroupMemberRepository;
|
||||||
|
private final GroupBatchRepository groupBatchRepository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public MigrationResult migrate() {
|
||||||
|
Map<String, Integer> recordsUpdated = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// Step 1: Create workspaces for users without one
|
||||||
|
int workspacesCreated = createWorkspacesForUsers();
|
||||||
|
|
||||||
|
// Build a userId → workspaceId lookup map
|
||||||
|
Map<String, UUID> userToWorkspace = buildUserToWorkspaceMap();
|
||||||
|
|
||||||
|
// Step 2: Backfill workspaceId on all 5 entities
|
||||||
|
recordsUpdated.put("Transaction", backfillTransactions(userToWorkspace));
|
||||||
|
recordsUpdated.put("Recipient", backfillRecipients(userToWorkspace));
|
||||||
|
recordsUpdated.put("RecipientGroup", backfillRecipientGroups(userToWorkspace));
|
||||||
|
recordsUpdated.put("RecipientGroupMember", backfillRecipientGroupMembers(userToWorkspace));
|
||||||
|
recordsUpdated.put("GroupBatch", backfillGroupBatches(userToWorkspace));
|
||||||
|
|
||||||
|
return MigrationResult.builder()
|
||||||
|
.workspacesCreated(workspacesCreated)
|
||||||
|
.recordsUpdated(recordsUpdated)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Step 1: Identify users without any workspace and create a default workspace for each.
|
||||||
|
* Returns the number of workspaces created.
|
||||||
|
*/
|
||||||
|
private int createWorkspacesForUsers() {
|
||||||
|
List<User> allUsers = userRepository.findAll();
|
||||||
|
int created = 0;
|
||||||
|
|
||||||
|
for (User user : allUsers) {
|
||||||
|
if (user.getWorkspaces() == null || user.getWorkspaces().isEmpty()) {
|
||||||
|
Workspace workspace = Workspace.builder()
|
||||||
|
.name(user.getUsername() + "'s Workspace")
|
||||||
|
.description("Default workspace for " + user.getUsername())
|
||||||
|
.users(new HashSet<>())
|
||||||
|
.build();
|
||||||
|
workspace.getUsers().add(user);
|
||||||
|
workspaceRepository.save(workspace);
|
||||||
|
created++;
|
||||||
|
log.info("Created workspace '{}' for user '{}'", workspace.getName(), user.getUsername());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Workspaces created: {}", created);
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a lookup map: userId (String) → workspaceId (UUID).
|
||||||
|
* Each user is mapped to their first workspace.
|
||||||
|
*/
|
||||||
|
private Map<String, UUID> buildUserToWorkspaceMap() {
|
||||||
|
Map<String, UUID> map = new HashMap<>();
|
||||||
|
List<User> allUsers = userRepository.findAll();
|
||||||
|
|
||||||
|
for (User user : allUsers) {
|
||||||
|
if (user.getWorkspaces() != null && !user.getWorkspaces().isEmpty()) {
|
||||||
|
Workspace firstWorkspace = user.getWorkspaces().iterator().next();
|
||||||
|
map.put(user.getId().toString(), firstWorkspace.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Built user→workspace map with {} entries", map.size());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backfill workspaceId on Transaction records that have userId but null workspaceId.
|
||||||
|
*/
|
||||||
|
private int backfillTransactions(Map<String, UUID> userToWorkspace) {
|
||||||
|
List<Transaction> records = transactionRepository.findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
|
int updated = 0;
|
||||||
|
|
||||||
|
for (Transaction record : records) {
|
||||||
|
UUID workspaceId = userToWorkspace.get(record.getUserId());
|
||||||
|
if (workspaceId != null) {
|
||||||
|
record.setWorkspaceId(workspaceId);
|
||||||
|
transactionRepository.save(record);
|
||||||
|
updated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Transactions backfilled: {}/{}", updated, records.size());
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backfill workspaceId on Recipient records that have userId but null workspaceId.
|
||||||
|
*/
|
||||||
|
private int backfillRecipients(Map<String, UUID> userToWorkspace) {
|
||||||
|
List<Recipient> records = recipientRepository.findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
|
int updated = 0;
|
||||||
|
|
||||||
|
for (Recipient record : records) {
|
||||||
|
UUID workspaceId = userToWorkspace.get(record.getUserId());
|
||||||
|
if (workspaceId != null) {
|
||||||
|
record.setWorkspaceId(workspaceId);
|
||||||
|
recipientRepository.save(record);
|
||||||
|
updated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Recipients backfilled: {}/{}", updated, records.size());
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backfill workspaceId on RecipientGroup records that have userId but null workspaceId.
|
||||||
|
*/
|
||||||
|
private int backfillRecipientGroups(Map<String, UUID> userToWorkspace) {
|
||||||
|
List<RecipientGroup> records = recipientGroupRepository.findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
|
int updated = 0;
|
||||||
|
|
||||||
|
for (RecipientGroup record : records) {
|
||||||
|
UUID workspaceId = userToWorkspace.get(record.getUserId());
|
||||||
|
if (workspaceId != null) {
|
||||||
|
record.setWorkspaceId(workspaceId);
|
||||||
|
recipientGroupRepository.save(record);
|
||||||
|
updated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("RecipientGroups backfilled: {}/{}", updated, records.size());
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backfill workspaceId on RecipientGroupMember records that have userId but null workspaceId.
|
||||||
|
*/
|
||||||
|
private int backfillRecipientGroupMembers(Map<String, UUID> userToWorkspace) {
|
||||||
|
List<RecipientGroupMember> records = recipientGroupMemberRepository.findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
|
int updated = 0;
|
||||||
|
|
||||||
|
for (RecipientGroupMember record : records) {
|
||||||
|
UUID workspaceId = userToWorkspace.get(record.getUserId());
|
||||||
|
if (workspaceId != null) {
|
||||||
|
record.setWorkspaceId(workspaceId);
|
||||||
|
recipientGroupMemberRepository.save(record);
|
||||||
|
updated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("RecipientGroupMembers backfilled: {}/{}", updated, records.size());
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backfill workspaceId on GroupBatch records that have userId but null workspaceId.
|
||||||
|
*/
|
||||||
|
private int backfillGroupBatches(Map<String, UUID> userToWorkspace) {
|
||||||
|
List<GroupBatch> records = groupBatchRepository.findAllByWorkspaceIdIsNullAndUserIdIsNotNull();
|
||||||
|
int updated = 0;
|
||||||
|
|
||||||
|
for (GroupBatch record : records) {
|
||||||
|
UUID workspaceId = userToWorkspace.get(record.getUserId());
|
||||||
|
if (workspaceId != null) {
|
||||||
|
record.setWorkspaceId(workspaceId);
|
||||||
|
groupBatchRepository.save(record);
|
||||||
|
updated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("GroupBatches backfilled: {}/{}", updated, records.size());
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public static class MigrationResult {
|
||||||
|
private int workspacesCreated;
|
||||||
|
private Map<String, Integer> recordsUpdated;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package zw.qantra.tm.domain.services;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import zw.qantra.tm.domain.models.User;
|
||||||
|
import zw.qantra.tm.domain.models.Workspace;
|
||||||
|
import zw.qantra.tm.domain.repositories.UserRepository;
|
||||||
|
import zw.qantra.tm.domain.repositories.WorkspaceRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WorkspaceService {
|
||||||
|
|
||||||
|
private final WorkspaceRepository workspaceRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
public Page<Workspace> getAllWorkspaces(Specification<Workspace> specification, Pageable pageable) {
|
||||||
|
return workspaceRepository.findAll(specification, pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Workspace> getWorkspace(UUID id) {
|
||||||
|
return workspaceRepository.findById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Workspace> searchByName(String name) {
|
||||||
|
return workspaceRepository.findByNameContainingIgnoreCase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Workspace createWorkspace(Workspace workspace) {
|
||||||
|
return workspaceRepository.save(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Workspace updateWorkspace(UUID id, Workspace workspace) {
|
||||||
|
if (workspaceRepository.existsById(id)) {
|
||||||
|
workspace.setId(id);
|
||||||
|
return workspaceRepository.save(workspace);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteWorkspace(UUID id) {
|
||||||
|
if (workspaceRepository.existsById(id)) {
|
||||||
|
workspaceRepository.deleteById(id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Optional<Workspace> associateUser(UUID workspaceId, UUID userId) {
|
||||||
|
Workspace workspace = workspaceRepository.findById(workspaceId).orElse(null);
|
||||||
|
User user = userRepository.findById(userId).orElse(null);
|
||||||
|
if (workspace == null || user == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
workspace.getUsers().add(user);
|
||||||
|
workspaceRepository.save(workspace);
|
||||||
|
return Optional.of(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Optional<Workspace> disassociateUser(UUID workspaceId, UUID userId) {
|
||||||
|
Workspace workspace = workspaceRepository.findById(workspaceId).orElse(null);
|
||||||
|
User user = userRepository.findById(userId).orElse(null);
|
||||||
|
if (workspace == null || user == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
workspace.getUsers().remove(user);
|
||||||
|
workspaceRepository.save(workspace);
|
||||||
|
return Optional.of(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Set<User> getWorkspaceUsers(UUID workspaceId) {
|
||||||
|
return workspaceRepository.findById(workspaceId)
|
||||||
|
.map(Workspace::getUsers)
|
||||||
|
.orElse(Set.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Set<Workspace> getUserWorkspaces(UUID userId) {
|
||||||
|
return userRepository.findById(userId)
|
||||||
|
.map(User::getWorkspaces)
|
||||||
|
.orElse(Set.of());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,14 +18,12 @@ import zw.qantra.tm.domain.dtos.*;
|
|||||||
import zw.qantra.tm.domain.dtos.erp.VelocityCustomerResponseDto;
|
import zw.qantra.tm.domain.dtos.erp.VelocityCustomerResponseDto;
|
||||||
import zw.qantra.tm.domain.models.Otp;
|
import zw.qantra.tm.domain.models.Otp;
|
||||||
import zw.qantra.tm.domain.models.User;
|
import zw.qantra.tm.domain.models.User;
|
||||||
import zw.qantra.tm.domain.services.NotificationService;
|
import zw.qantra.tm.domain.models.Workspace;
|
||||||
import zw.qantra.tm.domain.services.OtpService;
|
import zw.qantra.tm.domain.services.*;
|
||||||
import zw.qantra.tm.domain.services.UserService;
|
|
||||||
import io.nflow.engine.workflow.curated.State;
|
import io.nflow.engine.workflow.curated.State;
|
||||||
|
|
||||||
import jakarta.validation.ConstraintViolation;
|
import jakarta.validation.ConstraintViolation;
|
||||||
import jakarta.validation.Validator;
|
import jakarta.validation.Validator;
|
||||||
import zw.qantra.tm.domain.services.VelocityPaymentService;
|
|
||||||
import zw.qantra.tm.exceptions.AlreadyExistsException;
|
import zw.qantra.tm.exceptions.AlreadyExistsException;
|
||||||
import zw.qantra.tm.rest.RestService;
|
import zw.qantra.tm.rest.RestService;
|
||||||
|
|
||||||
@@ -51,6 +49,8 @@ public class RegistrationWorkflow extends WorkflowDefinition {
|
|||||||
private NotificationService notificationService;
|
private NotificationService notificationService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private VelocityPaymentService velocityPaymentService;
|
private VelocityPaymentService velocityPaymentService;
|
||||||
|
@Autowired
|
||||||
|
private WorkspaceService workspaceService;
|
||||||
|
|
||||||
public static final String TYPE = "registrationWorkflow";
|
public static final String TYPE = "registrationWorkflow";
|
||||||
|
|
||||||
@@ -60,6 +60,7 @@ public class RegistrationWorkflow extends WorkflowDefinition {
|
|||||||
public static final State VERIFY_OTP = new State("verifyOtp");
|
public static final State VERIFY_OTP = new State("verifyOtp");
|
||||||
public static final State RESEND_OTP = new State("resendOtp", WorkflowStateType.manual);
|
public static final State RESEND_OTP = new State("resendOtp", WorkflowStateType.manual);
|
||||||
public static final State OTP_SUCCESS = new State("otpSuccess");
|
public static final State OTP_SUCCESS = new State("otpSuccess");
|
||||||
|
public static final State CREATE_WORKSPACE = new State("createWorkspace");
|
||||||
public static final State UPDATE_ERP = new State("updateErp");
|
public static final State UPDATE_ERP = new State("updateErp");
|
||||||
public static final State FAILED = new State("failed", WorkflowStateType.manual);
|
public static final State FAILED = new State("failed", WorkflowStateType.manual);
|
||||||
public static final State DONE = new State("done", WorkflowStateType.end);
|
public static final State DONE = new State("done", WorkflowStateType.end);
|
||||||
@@ -72,7 +73,8 @@ public class RegistrationWorkflow extends WorkflowDefinition {
|
|||||||
permit(SEND_OTP, VERIFY_OTP);
|
permit(SEND_OTP, VERIFY_OTP);
|
||||||
permit(RESEND_OTP, VERIFY_OTP);
|
permit(RESEND_OTP, VERIFY_OTP);
|
||||||
permit(VERIFY_OTP, OTP_SUCCESS, FAILED);
|
permit(VERIFY_OTP, OTP_SUCCESS, FAILED);
|
||||||
permit(OTP_SUCCESS, UPDATE_ERP, FAILED);
|
permit(OTP_SUCCESS, CREATE_WORKSPACE, FAILED);
|
||||||
|
permit(CREATE_WORKSPACE, UPDATE_ERP, FAILED);
|
||||||
permit(UPDATE_ERP, DONE);
|
permit(UPDATE_ERP, DONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,9 +169,28 @@ public class RegistrationWorkflow extends WorkflowDefinition {
|
|||||||
return NextAction.moveToState(FAILED, "Failed to register user: " + e.getMessage());
|
return NextAction.moveToState(FAILED, "Failed to register user: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextAction.moveToState(UPDATE_ERP, "User creation successfully for: " + request.getUsername());
|
return NextAction.moveToState(CREATE_WORKSPACE, "User creation successfully for: " + request.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NextAction createWorkspace(StateExecution execution) {
|
||||||
|
log.info("Begin create workspace");
|
||||||
|
RegisterRequest registerRequest = execution.getVariable("registerRequest", RegisterRequest.class);
|
||||||
|
Workspace workspace = new Workspace();
|
||||||
|
workspace.setName(registerRequest.getFirstName() + "'s Workspace");
|
||||||
|
workspace.setDescription("Default Workspace");
|
||||||
|
workspace.setPhone(registerRequest.getPhone());
|
||||||
|
workspace.setEmail(registerRequest.getEmail());
|
||||||
|
workspace = workspaceService.createWorkspace(workspace);
|
||||||
|
|
||||||
|
User user = userService.fetchUserByUsername(registerRequest.getUsername());
|
||||||
|
workspace.setUsers(Set.of(user));
|
||||||
|
workspaceService.updateWorkspace(workspace.getId(), workspace);
|
||||||
|
log.info("Workspace created successfully");
|
||||||
|
|
||||||
|
return NextAction.moveToState(UPDATE_ERP, "Workspace creation successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public NextAction updateErp(StateExecution execution) {
|
public NextAction updateErp(StateExecution execution) {
|
||||||
RegisterRequest registerRequest = execution.getVariable("registerRequest", RegisterRequest.class);
|
RegisterRequest registerRequest = execution.getVariable("registerRequest", RegisterRequest.class);
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public class RecipientsUpdateHandler implements HandlerInterface {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if(transaction.getStatus() == Status.SUCCESS){
|
if(transaction.getStatus() == Status.SUCCESS){
|
||||||
List<Recipient> recipients = recipientService.getRecipient(transaction.getCreditAccount(), transaction.getUserId());
|
List<Recipient> recipients = recipientService.getRecipient(transaction.getCreditAccount(), transaction.getWorkspaceId());
|
||||||
|
|
||||||
Recipient recipient = null;
|
Recipient recipient = null;
|
||||||
if(!recipients.isEmpty()){
|
if(!recipients.isEmpty()){
|
||||||
@@ -30,6 +30,7 @@ public class RecipientsUpdateHandler implements HandlerInterface {
|
|||||||
recipient = new Recipient();
|
recipient = new Recipient();
|
||||||
recipient.setAccount(transaction.getCreditAccount());
|
recipient.setAccount(transaction.getCreditAccount());
|
||||||
recipient.setUserId(transaction.getUserId());
|
recipient.setUserId(transaction.getUserId());
|
||||||
|
recipient.setWorkspaceId(transaction.getWorkspaceId());
|
||||||
}
|
}
|
||||||
|
|
||||||
recipient.setLatestProviderLabel(transaction.getProviderLabel());
|
recipient.setLatestProviderLabel(transaction.getProviderLabel());
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public class ProviderSeeder implements Seeder {
|
|||||||
.requiresAccount(false)
|
.requiresAccount(false)
|
||||||
.requiresAmount(true)
|
.requiresAmount(true)
|
||||||
.requiresPhone(true)
|
.requiresPhone(true)
|
||||||
|
.requiresProducts(false)
|
||||||
.priority(2)
|
.priority(2)
|
||||||
.meta("{\"hotProductId\": \"101\"}")
|
.meta("{\"hotProductId\": \"101\"}")
|
||||||
.uid(Utils.getUid())
|
.uid(Utils.getUid())
|
||||||
@@ -60,6 +61,7 @@ public class ProviderSeeder implements Seeder {
|
|||||||
.requiresAccount(false)
|
.requiresAccount(false)
|
||||||
.requiresAmount(true)
|
.requiresAmount(true)
|
||||||
.requiresPhone(true)
|
.requiresPhone(true)
|
||||||
|
.requiresProducts(false)
|
||||||
.priority(2)
|
.priority(2)
|
||||||
.meta("{\"hotProductId\": \"7\"}")
|
.meta("{\"hotProductId\": \"7\"}")
|
||||||
.uid(Utils.getUid())
|
.uid(Utils.getUid())
|
||||||
@@ -79,6 +81,7 @@ public class ProviderSeeder implements Seeder {
|
|||||||
.requiresAccount(false)
|
.requiresAccount(false)
|
||||||
.requiresAmount(true)
|
.requiresAmount(true)
|
||||||
.requiresPhone(true)
|
.requiresPhone(true)
|
||||||
|
.requiresProducts(true)
|
||||||
.uid(Utils.getUid())
|
.uid(Utils.getUid())
|
||||||
.priority(3)
|
.priority(3)
|
||||||
.meta("{\"hotProductId\": \"35\"}")
|
.meta("{\"hotProductId\": \"35\"}")
|
||||||
@@ -98,6 +101,7 @@ public class ProviderSeeder implements Seeder {
|
|||||||
.requiresAccount(true)
|
.requiresAccount(true)
|
||||||
.requiresAmount(true)
|
.requiresAmount(true)
|
||||||
.requiresPhone(true)
|
.requiresPhone(true)
|
||||||
|
.requiresProducts(false)
|
||||||
.priority(1)
|
.priority(1)
|
||||||
.meta("{\"hotProductId\": \"24\"}")
|
.meta("{\"hotProductId\": \"24\"}")
|
||||||
.uid(Utils.getUid())
|
.uid(Utils.getUid())
|
||||||
@@ -117,6 +121,7 @@ public class ProviderSeeder implements Seeder {
|
|||||||
.requiresAccount(true)
|
.requiresAccount(true)
|
||||||
.requiresAmount(true)
|
.requiresAmount(true)
|
||||||
.requiresPhone(true)
|
.requiresPhone(true)
|
||||||
|
.requiresProducts(false)
|
||||||
.priority(1)
|
.priority(1)
|
||||||
.meta("{\"hotProductId\": \"41\"}")
|
.meta("{\"hotProductId\": \"41\"}")
|
||||||
.uid(Utils.getUid())
|
.uid(Utils.getUid())
|
||||||
@@ -136,6 +141,7 @@ public class ProviderSeeder implements Seeder {
|
|||||||
.requiresAccount(false)
|
.requiresAccount(false)
|
||||||
.requiresAmount(false)
|
.requiresAmount(false)
|
||||||
.requiresPhone(true)
|
.requiresPhone(true)
|
||||||
|
.requiresProducts(true)
|
||||||
.priority(4)
|
.priority(4)
|
||||||
.meta("{\"hotProductId\": \"111\"}")
|
.meta("{\"hotProductId\": \"111\"}")
|
||||||
.uid(Utils.getUid())
|
.uid(Utils.getUid())
|
||||||
@@ -156,6 +162,7 @@ public class ProviderSeeder implements Seeder {
|
|||||||
.requiresAmount(false)
|
.requiresAmount(false)
|
||||||
.requiresPhone(true)
|
.requiresPhone(true)
|
||||||
.requiresProducts(true)
|
.requiresProducts(true)
|
||||||
|
.requiresProducts(false)
|
||||||
.priority(4)
|
.priority(4)
|
||||||
.meta("{\"hotProductId\": \"16\"}")
|
.meta("{\"hotProductId\": \"16\"}")
|
||||||
.uid(Utils.getUid())
|
.uid(Utils.getUid())
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ mpgs.return-url=https://pay.velocityafrica.net/return
|
|||||||
|
|
||||||
# JWT Configuration
|
# JWT Configuration
|
||||||
jwt.secret=your-super-secret-jwt-key-here-make-it-very-long-and-secure-in-production
|
jwt.secret=your-super-secret-jwt-key-here-make-it-very-long-and-secure-in-production
|
||||||
jwt.expiration=86400000
|
jwt.expiration=7776000000
|
||||||
|
|
||||||
logging.level.root=WARN
|
logging.level.root=WARN
|
||||||
spring.datasource.nflow.url=jdbc:postgresql://62.171.179.108:5432/qpay-nflow
|
spring.datasource.nflow.url=jdbc:postgresql://62.171.179.108:5432/qpay-nflow
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import java.math.BigDecimal;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static java.util.UUID.randomUUID;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest
|
||||||
@@ -29,13 +31,14 @@ class TransactionRepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
@DisplayName("Should save and find transaction by ID")
|
@DisplayName("Should save and find transaction by ID")
|
||||||
void shouldSaveAndFindById() {
|
void shouldSaveAndFindById() {
|
||||||
Transaction transaction = createTestTransaction();
|
UUID wsId = randomUUID();
|
||||||
|
Transaction transaction = createTestTransaction(wsId);
|
||||||
Transaction saved = transactionRepository.save(transaction);
|
Transaction saved = transactionRepository.save(transaction);
|
||||||
|
|
||||||
Optional<Transaction> found = transactionRepository.findById(saved.getId());
|
Optional<Transaction> found = transactionRepository.findById(saved.getId());
|
||||||
|
|
||||||
assertTrue(found.isPresent());
|
assertTrue(found.isPresent());
|
||||||
assertEquals("user-1", found.get().getUserId());
|
assertEquals(wsId, found.get().getWorkspaceId());
|
||||||
assertEquals(new BigDecimal("100.00"), found.get().getAmount());
|
assertEquals(new BigDecimal("100.00"), found.get().getAmount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,19 +51,21 @@ class TransactionRepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Should find transactions by userId")
|
@DisplayName("Should find transactions by workspaceId")
|
||||||
void shouldFindByUserId() {
|
void shouldFindByWorkspaceId() {
|
||||||
|
UUID ws1 = randomUUID();
|
||||||
|
UUID ws2 = randomUUID();
|
||||||
Transaction tx1 = createTestTransaction();
|
Transaction tx1 = createTestTransaction();
|
||||||
tx1.setUserId("user-1");
|
tx1.setWorkspaceId(ws1);
|
||||||
Transaction tx2 = createTestTransaction();
|
Transaction tx2 = createTestTransaction();
|
||||||
tx2.setUserId("user-2");
|
tx2.setWorkspaceId(ws2);
|
||||||
transactionRepository.save(tx1);
|
transactionRepository.save(tx1);
|
||||||
transactionRepository.save(tx2);
|
transactionRepository.save(tx2);
|
||||||
|
|
||||||
var results = transactionRepository.findAllByUserId("user-1");
|
var results = transactionRepository.findAllByWorkspaceId(ws1);
|
||||||
|
|
||||||
assertEquals(1, results.size());
|
assertEquals(1, results.size());
|
||||||
assertEquals("user-1", results.get(0).getUserId());
|
assertEquals(ws1, results.get(0).getWorkspaceId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -68,7 +73,7 @@ class TransactionRepositoryTest {
|
|||||||
void shouldReturnPaginatedResults() {
|
void shouldReturnPaginatedResults() {
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
Transaction tx = createTestTransaction();
|
Transaction tx = createTestTransaction();
|
||||||
tx.setUserId("user-" + i);
|
tx.setWorkspaceId(randomUUID());
|
||||||
transactionRepository.save(tx);
|
transactionRepository.save(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +102,7 @@ class TransactionRepositoryTest {
|
|||||||
@DisplayName("Should persist all transaction fields correctly")
|
@DisplayName("Should persist all transaction fields correctly")
|
||||||
void shouldPersistAllFields() {
|
void shouldPersistAllFields() {
|
||||||
Transaction transaction = Transaction.builder()
|
Transaction transaction = Transaction.builder()
|
||||||
.userId("user-1")
|
.workspaceId(randomUUID())
|
||||||
.trace("TRACE-123")
|
.trace("TRACE-123")
|
||||||
.region("ZW")
|
.region("ZW")
|
||||||
.amount(new BigDecimal("150.00"))
|
.amount(new BigDecimal("150.00"))
|
||||||
@@ -134,7 +139,7 @@ class TransactionRepositoryTest {
|
|||||||
|
|
||||||
Optional<Transaction> found = transactionRepository.findById(saved.getId());
|
Optional<Transaction> found = transactionRepository.findById(saved.getId());
|
||||||
assertTrue(found.isPresent());
|
assertTrue(found.isPresent());
|
||||||
assertEquals("user-1", found.get().getUserId());
|
assertNotNull(found.get().getWorkspaceId());
|
||||||
assertEquals(new BigDecimal("150.00"), found.get().getAmount());
|
assertEquals(new BigDecimal("150.00"), found.get().getAmount());
|
||||||
assertEquals(new BigDecimal("5.00"), found.get().getCharge());
|
assertEquals(new BigDecimal("5.00"), found.get().getCharge());
|
||||||
assertEquals(new BigDecimal("158.50"), found.get().getTotalAmount());
|
assertEquals(new BigDecimal("158.50"), found.get().getTotalAmount());
|
||||||
@@ -146,8 +151,12 @@ class TransactionRepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Transaction createTestTransaction() {
|
private Transaction createTestTransaction() {
|
||||||
|
return createTestTransaction(randomUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Transaction createTestTransaction(UUID workspaceId) {
|
||||||
return Transaction.builder()
|
return Transaction.builder()
|
||||||
.userId("user-1")
|
.workspaceId(workspaceId)
|
||||||
.amount(new BigDecimal("100.00"))
|
.amount(new BigDecimal("100.00"))
|
||||||
.debitCurrency(CurrencyType.USD)
|
.debitCurrency(CurrencyType.USD)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static java.util.UUID.randomUUID;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
@@ -55,7 +57,7 @@ class TransactionServiceTest {
|
|||||||
void setUp() {
|
void setUp() {
|
||||||
transaction = new Transaction();
|
transaction = new Transaction();
|
||||||
transaction.setId(txId);
|
transaction.setId(txId);
|
||||||
transaction.setUserId("user-1");
|
transaction.setWorkspaceId(randomUUID());
|
||||||
transaction.setAmount(new BigDecimal("100.00"));
|
transaction.setAmount(new BigDecimal("100.00"));
|
||||||
transaction.setDebitCurrency(CurrencyType.USD);
|
transaction.setDebitCurrency(CurrencyType.USD);
|
||||||
transaction.setCreditCurrency(CurrencyType.ZWL);
|
transaction.setCreditCurrency(CurrencyType.ZWL);
|
||||||
@@ -142,15 +144,17 @@ class TransactionServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Should reassign transactions from old user to new user")
|
@DisplayName("Should reassign transactions from old workspace to new workspace")
|
||||||
void shouldReassignTransactions() {
|
void shouldReassignTransactions() {
|
||||||
|
UUID oldWs = randomUUID();
|
||||||
|
UUID newWs = randomUUID();
|
||||||
List<Transaction> transactions = List.of(transaction);
|
List<Transaction> transactions = List.of(transaction);
|
||||||
when(transactionRepository.findAllByUserId("old-user")).thenReturn(transactions);
|
when(transactionRepository.findAllByWorkspaceId(oldWs)).thenReturn(transactions);
|
||||||
when(transactionRepository.save(any(Transaction.class))).thenReturn(transaction);
|
when(transactionRepository.save(any(Transaction.class))).thenReturn(transaction);
|
||||||
|
|
||||||
transactionService.reassignTransactions("old-user", "new-user");
|
transactionService.reassignTransactions(oldWs, newWs);
|
||||||
|
|
||||||
assertEquals("new-user", transaction.getUserId());
|
assertEquals(newWs, transaction.getWorkspaceId());
|
||||||
verify(transactionRepository).save(transaction);
|
verify(transactionRepository).save(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import zw.qantra.tm.domain.models.Transaction;
|
|||||||
import zw.qantra.tm.domain.services.RecipientService;
|
import zw.qantra.tm.domain.services.RecipientService;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static java.util.UUID.randomUUID;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -34,7 +37,7 @@ class RecipientsUpdateHandlerTest {
|
|||||||
transaction = new Transaction();
|
transaction = new Transaction();
|
||||||
transaction.setStatus(Status.SUCCESS);
|
transaction.setStatus(Status.SUCCESS);
|
||||||
transaction.setCreditAccount("ACC-123");
|
transaction.setCreditAccount("ACC-123");
|
||||||
transaction.setUserId("user-1");
|
transaction.setWorkspaceId(randomUUID());
|
||||||
transaction.setProviderLabel("econet");
|
transaction.setProviderLabel("econet");
|
||||||
transaction.setCreditName("John Doe");
|
transaction.setCreditName("John Doe");
|
||||||
transaction.setCreditEmail("john@example.com");
|
transaction.setCreditEmail("john@example.com");
|
||||||
@@ -47,10 +50,10 @@ class RecipientsUpdateHandlerTest {
|
|||||||
void shouldUpdateExistingRecipient() {
|
void shouldUpdateExistingRecipient() {
|
||||||
Recipient existingRecipient = new Recipient();
|
Recipient existingRecipient = new Recipient();
|
||||||
existingRecipient.setAccount("ACC-123");
|
existingRecipient.setAccount("ACC-123");
|
||||||
existingRecipient.setUserId("user-1");
|
existingRecipient.setWorkspaceId(randomUUID());
|
||||||
existingRecipient.setName("Old Name");
|
existingRecipient.setName("Old Name");
|
||||||
|
|
||||||
when(recipientService.getRecipient("ACC-123", "user-1"))
|
when(recipientService.getRecipient("ACC-123", transaction.getWorkspaceId()))
|
||||||
.thenReturn(List.of(existingRecipient));
|
.thenReturn(List.of(existingRecipient));
|
||||||
when(recipientService.save(any(Recipient.class))).thenReturn(existingRecipient);
|
when(recipientService.save(any(Recipient.class))).thenReturn(existingRecipient);
|
||||||
|
|
||||||
@@ -68,7 +71,7 @@ class RecipientsUpdateHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
@DisplayName("Should create new recipient when not found")
|
@DisplayName("Should create new recipient when not found")
|
||||||
void shouldCreateNewRecipient() {
|
void shouldCreateNewRecipient() {
|
||||||
when(recipientService.getRecipient("ACC-123", "user-1"))
|
when(recipientService.getRecipient("ACC-123", transaction.getWorkspaceId()))
|
||||||
.thenReturn(List.of());
|
.thenReturn(List.of());
|
||||||
when(recipientService.save(any(Recipient.class))).thenAnswer(i -> i.getArgument(0));
|
when(recipientService.save(any(Recipient.class))).thenAnswer(i -> i.getArgument(0));
|
||||||
|
|
||||||
@@ -94,7 +97,7 @@ class RecipientsUpdateHandlerTest {
|
|||||||
void shouldUseBillNameForInitials() {
|
void shouldUseBillNameForInitials() {
|
||||||
transaction.setCreditName(null);
|
transaction.setCreditName(null);
|
||||||
|
|
||||||
when(recipientService.getRecipient("ACC-123", "user-1"))
|
when(recipientService.getRecipient("ACC-123", transaction.getWorkspaceId()))
|
||||||
.thenReturn(List.of());
|
.thenReturn(List.of());
|
||||||
when(recipientService.save(any(Recipient.class))).thenAnswer(i -> i.getArgument(0));
|
when(recipientService.save(any(Recipient.class))).thenAnswer(i -> i.getArgument(0));
|
||||||
|
|
||||||
@@ -106,7 +109,7 @@ class RecipientsUpdateHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
@DisplayName("Should handle exception gracefully without throwing")
|
@DisplayName("Should handle exception gracefully without throwing")
|
||||||
void shouldHandleExceptionGracefully() {
|
void shouldHandleExceptionGracefully() {
|
||||||
when(recipientService.getRecipient("ACC-123", "user-1"))
|
when(recipientService.getRecipient("ACC-123", transaction.getWorkspaceId()))
|
||||||
.thenThrow(new RuntimeException("DB error"));
|
.thenThrow(new RuntimeException("DB error"));
|
||||||
|
|
||||||
assertDoesNotThrow(() -> handler.process(transaction));
|
assertDoesNotThrow(() -> handler.process(transaction));
|
||||||
@@ -121,9 +124,9 @@ class RecipientsUpdateHandlerTest {
|
|||||||
|
|
||||||
Recipient existingRecipient = new Recipient();
|
Recipient existingRecipient = new Recipient();
|
||||||
existingRecipient.setAccount("ACC-123");
|
existingRecipient.setAccount("ACC-123");
|
||||||
existingRecipient.setUserId("user-1");
|
existingRecipient.setWorkspaceId(randomUUID());
|
||||||
|
|
||||||
when(recipientService.getRecipient("ACC-123", "user-1"))
|
when(recipientService.getRecipient("ACC-123", transaction.getWorkspaceId()))
|
||||||
.thenReturn(List.of(existingRecipient));
|
.thenReturn(List.of(existingRecipient));
|
||||||
when(recipientService.save(any(Recipient.class))).thenReturn(existingRecipient);
|
when(recipientService.save(any(Recipient.class))).thenReturn(existingRecipient);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user