Add various delete methods

Add delete methods for transactions and recurring transactions. Also add
 open/close methods for accounts. Add unit tests for all new methods.
 Also JAXB is no longer a provided dependency for build-war.
This commit is contained in:
2019-03-15 20:24:47 +01:00
parent ab7fb15254
commit e9774b3b35
14 changed files with 567 additions and 8 deletions

View File

@@ -25,7 +25,11 @@ public enum ResponseReason {
INVALID_LAST_OCCURRENCE_FORMAT(HttpStatus.INTERNAL_SERVER_ERROR),
MISSING_RECURRING_TRANSACTION_ID(HttpStatus.INTERNAL_SERVER_ERROR),
INVALID_RECURRING_TRANSACTION_ID(HttpStatus.INTERNAL_SERVER_ERROR),
RECURRING_TRANSACTION_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR);
RECURRING_TRANSACTION_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR),
MISSING_TRANSACTION_ID(HttpStatus.INTERNAL_SERVER_ERROR),
INVALID_TRANSACTION_ID(HttpStatus.INTERNAL_SERVER_ERROR),
TRANSACTION_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR),
ACCOUNT_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR);
private HttpStatus httpStatus;

View File

@@ -53,4 +53,34 @@ public class AccountController {
return responseReason.toResponseEntity();
}
@RequestMapping("closeAccount")
public ResponseEntity closeAccount(String key) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("/accounts/closeAccount got parameters: %s", key));
}
final ResponseReason responseReason = this.accountService.closeAccount(key);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("/accounts/closeAccount returns with %s", responseReason.name()));
}
return responseReason.toResponseEntity();
}
@RequestMapping("openAccount")
public ResponseEntity openAccount(String key) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("/accounts/openAccount got parameters: %s", key));
}
final ResponseReason responseReason = this.accountService.openAccount(key);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("/accounts/openAccount returns with %s", responseReason.name()));
}
return responseReason.toResponseEntity();
}
}

View File

@@ -80,4 +80,23 @@ public class RecurringTransactionController {
return responseReason.toResponseEntity();
}
@RequestMapping("deleteRecurringTransaction")
public ResponseEntity deleteRecurringTransaction(String recurringTransactionId) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String
.format("/recurringTransactions/deleteRecurringTransaction got parameters: %s",
recurringTransactionId));
}
final ResponseReason responseReason = this.recurringTransactionService
.deleteRecurringTransaction(recurringTransactionId);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String
.format("/recurringTransactions/deleteRecurringTransaction returns with %s", responseReason.name()));
}
return responseReason.toResponseEntity();
}
}

View File

@@ -47,4 +47,23 @@ public class TransactionController {
return responseReason.toResponseEntity();
}
@RequestMapping("deleteTransaction")
public ResponseEntity deleteTransaction(String transactionId) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String
.format("/transactions/deleteTransaction got parameters: %s",
transactionId));
}
final ResponseReason responseReason = this.transactionService
.deleteTransaction(transactionId);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String
.format("/transactions/deleteTransaction returns with %s", responseReason.name()));
}
return responseReason.toResponseEntity();
}
}

View File

@@ -1,8 +1,20 @@
package de.financer.model;
import java.util.Arrays;
public enum AccountStatus {
/** Indicates that the account is open for bookings */
OPEN,
/** Indicates that the account is closed and bookings to it are forbidden */
CLOSED
CLOSED;
/**
* This method validates whether the given string represents a valid account status.
*
* @param status to check
* @return whether the given status represents a valid account status
*/
public static boolean isValidType(String status) {
return Arrays.stream(AccountStatus.values()).anyMatch((accountStatus) -> accountStatus.name().equals(status));
}
}

View File

@@ -106,4 +106,40 @@ public class AccountService {
return ResponseReason.OK;
}
@Transactional(propagation = Propagation.REQUIRED)
public ResponseReason closeAccount(String key) {
return setAccountStatus(key, AccountStatus.CLOSED);
}
@Transactional(propagation = Propagation.REQUIRED)
public ResponseReason openAccount(String key) {
return setAccountStatus(key, AccountStatus.OPEN);
}
// Visible for unit tests
/* package */ ResponseReason setAccountStatus(String key, AccountStatus accountStatus) {
if (!StringUtils.startsWith(key, "accounts.")) {
return ResponseReason.INVALID_ACCOUNT_KEY;
}
final Account account = this.accountRepository.findByKey(key);
if (account == null) {
return ResponseReason.ACCOUNT_NOT_FOUND;
}
account.setStatus(accountStatus);
try {
this.accountRepository.save(account);
}
catch (Exception e) {
LOGGER.error(String.format("Could not update account status %s|%s", key, accountStatus.name()), e);
return ResponseReason.UNKNOWN_ERROR;
}
return ResponseReason.OK;
}
}

View File

@@ -387,4 +387,33 @@ public class RecurringTransactionService {
recurringTransaction.getDescription(),
recurringTransaction);
}
@Transactional(propagation = Propagation.REQUIRED)
public ResponseReason deleteRecurringTransaction(String recurringTransactionId) {
ResponseReason response = ResponseReason.OK;
if (recurringTransactionId == null) {
return ResponseReason.MISSING_RECURRING_TRANSACTION_ID;
} else if (!NumberUtils.isCreatable(recurringTransactionId)) {
return ResponseReason.INVALID_RECURRING_TRANSACTION_ID;
}
final Optional<RecurringTransaction> optionalRecurringTransaction = this.recurringTransactionRepository
.findById(Long.valueOf(recurringTransactionId));
if (!optionalRecurringTransaction.isPresent()) {
return ResponseReason.RECURRING_TRANSACTION_NOT_FOUND;
}
try {
this.recurringTransactionRepository.deleteById(Long.valueOf(recurringTransactionId));
}
catch (Exception e) {
LOGGER.error("Could not delete recurring transaction!", e);
response = ResponseReason.UNKNOWN_ERROR;
}
return response;
}
}

View File

@@ -6,6 +6,7 @@ import de.financer.dba.TransactionRepository;
import de.financer.model.Account;
import de.financer.model.RecurringTransaction;
import de.financer.model.Transaction;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -17,6 +18,7 @@ import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Collections;
import java.util.Optional;
@Service
public class TransactionService {
@@ -168,4 +170,48 @@ public class TransactionService {
return response;
}
@Transactional(propagation = Propagation.REQUIRED)
public ResponseReason deleteTransaction(String transactionId) {
ResponseReason response = ResponseReason.OK;
if (transactionId == null) {
return ResponseReason.MISSING_TRANSACTION_ID;
} else if (!NumberUtils.isCreatable(transactionId)) {
return ResponseReason.INVALID_TRANSACTION_ID;
}
final Optional<Transaction> optionalTransaction = this.transactionRepository
.findById(Long.valueOf(transactionId));
if (!optionalTransaction.isPresent()) {
return ResponseReason.TRANSACTION_NOT_FOUND;
}
final Transaction transaction = optionalTransaction.get();
final Account fromAccount = transaction.getFromAccount();
final Account toAccount = transaction.getToAccount();
final Long amount = transaction.getAmount();
// Invert the actual multiplier by multiplying with -1
// If we delete a transaction we do the inverse of the original transaction
fromAccount.setCurrentBalance(fromAccount.getCurrentBalance() + (this.ruleService
.getMultiplierFromAccount(fromAccount) * amount * -1));
toAccount.setCurrentBalance(toAccount.getCurrentBalance() + (this.ruleService
.getMultiplierToAccount(toAccount) * amount * -1));
try {
this.transactionRepository.deleteById(Long.valueOf(transactionId));
this.accountService.saveAccount(fromAccount);
this.accountService.saveAccount(toAccount);
}
catch (Exception e) {
LOGGER.error("Could not delete transaction!", e);
response = ResponseReason.UNKNOWN_ERROR;
}
return response;
}
}