Skip to content

Commit

Permalink
feat: ability to reject multiple transactions.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mateusz Czeladka committed Aug 7, 2024
1 parent 0d942c7 commit f0d6901
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 228 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.domain.core;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.zalando.problem.Problem;

@RequiredArgsConstructor
@ToString
@Getter
public class TransactionProblem {

private final String id;
private final Problem problem;

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionProblem;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionType;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Rejection;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionApprove;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsApprove;
import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.LedgerService;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zalando.problem.Problem;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus.FAILED;
import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus.FAIL;
import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW;

@Service
@Slf4j
Expand All @@ -30,118 +36,135 @@ public class TransactionRepositoryGateway {
private final TransactionRepository transactionRepository;
private final LedgerService ledgerService;

@Transactional
public Either<Problem, Boolean> approveTransaction(String transactionId) {
@Transactional(propagation = REQUIRES_NEW)
// TODO optimise performance because we have to load transaction from db each time and we don't save it in bulk
private Either<TransactionProblem, TransactionEntity> approveTransaction(String transactionId) {
log.info("Approving transaction: {}", transactionId);

val txM = transactionRepository.findById(transactionId);

if (txM.isEmpty()) {
return Either.left(Problem.builder()
val problem = Problem.builder()
.withTitle("TX_NOT_FOUND")
.withDetail(STR."Transaction with id \{transactionId} not found")
.with("transactionId", transactionId)
.build()
);
.build();

return Either.left(new TransactionProblem(transactionId, problem));
}

val tx = txM.orElseThrow();

if (tx.getAutomatedValidationStatus() == FAILED) {
return Either.left(Problem.builder()
if (tx.getStatus() == FAIL) {
val problem = Problem.builder()
.withTitle("CANNOT_APPROVE_FAILED_TX")
.withDetail(STR."Cannot approve a failed transaction, transactionId: \{transactionId}")
.with("transactionId", transactionId)
.build()
);
.build();

return Either.left(new TransactionProblem(transactionId, problem));
}

tx.setTransactionApproved(true);

val savedTx = transactionRepository.save(tx);
val organisationId = savedTx.getOrganisation().getId();

if (savedTx.getTransactionApproved()) {
ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, Set.of(savedTx));

return Either.right(savedTx.getTransactionApproved());
}

return Either.right(false);
return Either.right(savedTx);
}

@Transactional
public Set<String> approveTransactions(String organisationId, Set<String> transactionIds) {
log.info("Approving transactions: {}", transactionIds);
public List<Either<TransactionProblem, TransactionEntity>> approveTransactions(TransactionsApprove transactionsApprove) {
val organisationId = transactionsApprove.getOrganisationId();

val transactions = transactionRepository.findAllById(transactionIds)
val transactionIds = transactionsApprove.getTransactionApproves()
.stream()
.filter(tx -> tx.getAutomatedValidationStatus() != FAILED)
.peek(tx -> tx.setTransactionApproved(true))
.map(TransactionApprove::getId)
.collect(Collectors.toSet());

val savedTxs = transactionRepository.saveAll(transactions);
val transactionsApprovalResponseListE = new ArrayList<Either<TransactionProblem, TransactionEntity>>();
for (val transactionId : transactionIds) {
try {
val transactionEntities = approveTransaction(transactionId);

ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, Set.copyOf(savedTxs));
transactionsApprovalResponseListE.add(transactionEntities);
} catch (DataAccessException dae) {
log.error("Error approving transaction: {}", transactionId, dae);

return savedTxs.stream().map(TransactionEntity::getId).collect(Collectors.toSet());
}
val problem = Problem.builder()
.withTitle("DB_ERROR")
.withDetail(STR."DB error approving transaction: \{transactionId}")
.with("transactionId", transactionId)
.with("error", dae.getMessage())
.build();

@Transactional
public Set<String> approveTransactionsDispatch(String organisationId, Set<String> transactionIds) {
log.info("Approving transactions dispatch: {}", transactionIds);
transactionsApprovalResponseListE.add(Either.left(new TransactionProblem(transactionId, problem)));
}
}

val transactions = transactionRepository.findAllById(transactionIds)
.stream()
.filter(tx -> tx.getAutomatedValidationStatus() != FAILED)
.peek(tx -> tx.setLedgerDispatchApproved(true))
val transactionSuccesses = transactionsApprovalResponseListE.stream()
.filter(Either::isRight)
.map(Either::get)
.collect(Collectors.toSet());

val savedTxs = transactionRepository.saveAll(transactions);

ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, Set.copyOf(savedTxs));
ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, transactionSuccesses);

return savedTxs.stream().map(TransactionEntity::getId).collect(Collectors.toSet());
return transactionsApprovalResponseListE;
}

@Transactional
public Either<Problem, Boolean> approveTransactionDispatch(String transactionId) {
log.info("Approving transaction dispatch: {}", transactionId);

val txM = transactionRepository.findById(transactionId);

if (txM.isEmpty()) {
return Either.left(Problem.builder()
.withTitle("TX_NOT_FOUND")
.withDetail(STR."Transaction with id \{transactionId} not found")
.with("transactionId", transactionId)
.build()
);
}

val tx = txM.orElseThrow();

if (tx.getAutomatedValidationStatus() == FAILED) {
return Either.left(Problem.builder()
.withTitle("CANNOT_APPROVE_FAILED_TX")
.withDetail(STR."Cannot approve dispatch for a failed transaction, transactionId: \{transactionId}")
.with("transactionId", transactionId)
.build()
);
}

tx.setLedgerDispatchApproved(true);

val savedTx = transactionRepository.save(tx);

if (savedTx.getLedgerDispatchApproved()) {
ledgerService.checkIfThereAreTransactionsToDispatch(savedTx.getOrganisation().getId(), Set.of(savedTx));

return Either.right(savedTx.getLedgerDispatchApproved());
}

return Either.right(false);
}
// @Transactional
// public Set<String> approveTransactionsDispatch(String organisationId, Set<String> transactionIds) {
// log.info("Approving transactions dispatch: {}", transactionIds);
//
// val transactions = transactionRepository.findAllById(transactionIds)
// .stream()
// .filter(tx -> tx.getAutomatedValidationStatus() != FAILED)
// .peek(tx -> tx.setLedgerDispatchApproved(true))
// .collect(Collectors.toSet());
//
// val savedTxs = transactionRepository.saveAll(transactions);
//
// ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, Set.copyOf(savedTxs));
//
// return savedTxs.stream().map(TransactionEntity::getId).collect(Collectors.toSet());
// }

// @Transactional
// public Either<Problem, Boolean> approveTransactionDispatch(String transactionId) {
// log.info("Approving transaction dispatch: {}", transactionId);
//
// val txM = transactionRepository.findById(transactionId);
//
// if (txM.isEmpty()) {
// return Either.left(Problem.builder()
// .withTitle("TX_NOT_FOUND")
// .withDetail(STR."Transaction with id \{transactionId} not found")
// .with("transactionId", transactionId)
// .build()
// );
// }
//
// val tx = txM.orElseThrow();
//
// if (tx.getAutomatedValidationStatus() == FAILED) {
// return Either.left(Problem.builder()
// .withTitle("CANNOT_APPROVE_FAILED_TX")
// .withDetail(STR."Cannot approve dispatch for a failed transaction, transactionId: \{transactionId}")
// .with("transactionId", transactionId)
// .build()
// );
// }
//
// tx.setLedgerDispatchApproved(true);
//
// val savedTx = transactionRepository.save(tx);
//
// if (savedTx.getLedgerDispatchApproved()) {
// ledgerService.checkIfThereAreTransactionsToDispatch(savedTx.getOrganisation().getId(), Set.of(savedTx));
//
// return Either.right(savedTx.getLedgerDispatchApproved());
// }
//
// return Either.right(false);
// }

public Either<Problem, Boolean> changeTransactionComment(String txId, String userComment) {
val txM = transactionRepository.findById(txId);
Expand Down Expand Up @@ -205,16 +228,15 @@ public Optional<TransactionEntity> findById(String transactionId) {
}

public List<TransactionEntity> findByAllId(Set<String> transactionIds) {

return transactionRepository.findAllById(transactionIds);
}

private static Set<String> transactionIds(Set<TransactionEntity> transactions) {
return transactions
.stream()
.map(TransactionEntity::getId)
.collect(Collectors.toSet());
}
// private static Set<String> transactionIds(Set<TransactionEntity> transactions) {
// return transactions
// .stream()
// .map(TransactionEntity::getId)
// .collect(Collectors.toSet());
// }

public List<TransactionEntity> findAllByStatus(String organisationId,
List<ValidationStatus> validationStatuses,
Expand All @@ -225,4 +247,5 @@ public List<TransactionEntity> findAllByStatus(String organisationId,
public List<TransactionEntity> listAll() {
return transactionRepository.findAll();
}

}
Loading

0 comments on commit f0d6901

Please sign in to comment.