From e9774b3b35a024647bdff120350f69dff34f8390 Mon Sep 17 00:00:00 2001 From: MK13 Date: Fri, 15 Mar 2019 20:24:47 +0100 Subject: [PATCH] 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. --- pom.xml | 5 - src/main/java/de/financer/ResponseReason.java | 6 +- .../controller/AccountController.java | 30 ++++ .../RecurringTransactionController.java | 19 +++ .../controller/TransactionController.java | 19 +++ .../java/de/financer/model/AccountStatus.java | 14 +- .../de/financer/service/AccountService.java | 36 +++++ .../service/RecurringTransactionService.java | 29 ++++ .../financer/service/TransactionService.java | 46 +++++++ ...nsactionService_getAllIntegrationTest.java | 2 +- .../AccountService_createAccountTest.java | 72 ++++++++++ .../AccountService_setAccountStatusTest.java | 74 ++++++++++ ...ervice_deleteRecurringTransactionTest.java | 94 +++++++++++++ ...nsactionService_deleteTransactionTest.java | 129 ++++++++++++++++++ 14 files changed, 567 insertions(+), 8 deletions(-) create mode 100644 src/test/java/de/financer/service/AccountService_createAccountTest.java create mode 100644 src/test/java/de/financer/service/AccountService_setAccountStatusTest.java create mode 100644 src/test/java/de/financer/service/RecurringTransactionService_deleteRecurringTransactionTest.java create mode 100644 src/test/java/de/financer/service/TransactionService_deleteTransactionTest.java diff --git a/pom.xml b/pom.xml index 54c048d..e38c2cd 100644 --- a/pom.xml +++ b/pom.xml @@ -166,11 +166,6 @@ spring-boot-starter-tomcat provided - - org.glassfish.jaxb - jaxb-runtime - provided - diff --git a/src/main/java/de/financer/ResponseReason.java b/src/main/java/de/financer/ResponseReason.java index 35d12e4..d531686 100644 --- a/src/main/java/de/financer/ResponseReason.java +++ b/src/main/java/de/financer/ResponseReason.java @@ -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; diff --git a/src/main/java/de/financer/controller/AccountController.java b/src/main/java/de/financer/controller/AccountController.java index 202aeef..22103d2 100644 --- a/src/main/java/de/financer/controller/AccountController.java +++ b/src/main/java/de/financer/controller/AccountController.java @@ -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(); + } } diff --git a/src/main/java/de/financer/controller/RecurringTransactionController.java b/src/main/java/de/financer/controller/RecurringTransactionController.java index cd78932..c63a27f 100644 --- a/src/main/java/de/financer/controller/RecurringTransactionController.java +++ b/src/main/java/de/financer/controller/RecurringTransactionController.java @@ -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(); + } } diff --git a/src/main/java/de/financer/controller/TransactionController.java b/src/main/java/de/financer/controller/TransactionController.java index 8ddbb58..276a3f4 100644 --- a/src/main/java/de/financer/controller/TransactionController.java +++ b/src/main/java/de/financer/controller/TransactionController.java @@ -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(); + } } diff --git a/src/main/java/de/financer/model/AccountStatus.java b/src/main/java/de/financer/model/AccountStatus.java index a60151f..9298e31 100644 --- a/src/main/java/de/financer/model/AccountStatus.java +++ b/src/main/java/de/financer/model/AccountStatus.java @@ -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)); + } } diff --git a/src/main/java/de/financer/service/AccountService.java b/src/main/java/de/financer/service/AccountService.java index 511dec0..58864c3 100644 --- a/src/main/java/de/financer/service/AccountService.java +++ b/src/main/java/de/financer/service/AccountService.java @@ -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; + } } diff --git a/src/main/java/de/financer/service/RecurringTransactionService.java b/src/main/java/de/financer/service/RecurringTransactionService.java index 4daf71a..4d35cce 100644 --- a/src/main/java/de/financer/service/RecurringTransactionService.java +++ b/src/main/java/de/financer/service/RecurringTransactionService.java @@ -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 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; + } } diff --git a/src/main/java/de/financer/service/TransactionService.java b/src/main/java/de/financer/service/TransactionService.java index 6e8865a..70da78a 100644 --- a/src/main/java/de/financer/service/TransactionService.java +++ b/src/main/java/de/financer/service/TransactionService.java @@ -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 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; + } } diff --git a/src/test/java/de/financer/controller/integration/RecurringTransactionService_getAllIntegrationTest.java b/src/test/java/de/financer/controller/integration/RecurringTransactionService_getAllIntegrationTest.java index 021ad2e..984d673 100644 --- a/src/test/java/de/financer/controller/integration/RecurringTransactionService_getAllIntegrationTest.java +++ b/src/test/java/de/financer/controller/integration/RecurringTransactionService_getAllIntegrationTest.java @@ -43,7 +43,7 @@ public class RecurringTransactionService_getAllIntegrationTest { final List allRecurringTransactions = this.objectMapper .readValue(mvcResult.getResponse().getContentAsByteArray(), new TypeReference>() {}); - Assert.assertEquals(2, allRecurringTransactions.size()); + Assert.assertEquals(3, allRecurringTransactions.size()); } } diff --git a/src/test/java/de/financer/service/AccountService_createAccountTest.java b/src/test/java/de/financer/service/AccountService_createAccountTest.java new file mode 100644 index 0000000..38daec8 --- /dev/null +++ b/src/test/java/de/financer/service/AccountService_createAccountTest.java @@ -0,0 +1,72 @@ +package de.financer.service; + +import de.financer.ResponseReason; +import de.financer.dba.AccountRepository; +import de.financer.model.Account; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class AccountService_createAccountTest { + @InjectMocks + private AccountService classUnderTest; + + @Mock + private AccountRepository accountRepository; + + @Test + public void test_createAccount_INVALID_ACCOUNT_TYPE() { + // Arrange + // Nothing to do + + // Act + ResponseReason response = this.classUnderTest.createAccount(null, null); + + // Assert + Assert.assertEquals(ResponseReason.INVALID_ACCOUNT_TYPE, response); + } + + @Test + public void test_createAccount_INVALID_ACCOUNT_KEY() { + // Arrange + // Nothing to do + + // Act + ResponseReason response = this.classUnderTest.createAccount(null, "BANK"); + + // Assert + Assert.assertEquals(ResponseReason.INVALID_ACCOUNT_KEY, response); + } + + @Test + public void test_createAccount_UNKNOWN_ERROR() { + // Arrange + Mockito.doThrow(new NullPointerException()).when(this.accountRepository).save(Mockito.any(Account.class)); + + // Act + ResponseReason response = this.classUnderTest.createAccount("accounts.test", "BANK"); + + // Assert + Assert.assertEquals(ResponseReason.UNKNOWN_ERROR, response); + } + + @Test + public void test_createAccount_OK() { + // Arrange + // Nothing to do + + // Act + ResponseReason response = this.classUnderTest.createAccount("accounts.test", "BANK"); + + // Assert + Assert.assertEquals(ResponseReason.OK, response); + Mockito.verify(this.accountRepository, Mockito.times(1)) + .save(ArgumentMatchers.argThat((acc) -> "accounts.test".equals(acc.getKey()))); + } +} diff --git a/src/test/java/de/financer/service/AccountService_setAccountStatusTest.java b/src/test/java/de/financer/service/AccountService_setAccountStatusTest.java new file mode 100644 index 0000000..880fff8 --- /dev/null +++ b/src/test/java/de/financer/service/AccountService_setAccountStatusTest.java @@ -0,0 +1,74 @@ +package de.financer.service; + +import de.financer.ResponseReason; +import de.financer.dba.AccountRepository; +import de.financer.model.Account; +import de.financer.model.AccountStatus; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class AccountService_setAccountStatusTest { + @InjectMocks + private AccountService classUnderTest; + + @Mock + private AccountRepository accountRepository; + + @Test + public void test_setAccountStatus_INVALID_ACCOUNT_KEY() { + // Arrange + // Nothing to do + + // Act + ResponseReason response = this.classUnderTest.setAccountStatus(null, AccountStatus.CLOSED); + + // Assert + Assert.assertEquals(ResponseReason.INVALID_ACCOUNT_KEY, response); + } + + @Test + public void test_setAccountStatus_ACCOUNT_NOT_FOUND() { + // Arrange + // Nothing to do + + // Act + ResponseReason response = this.classUnderTest.setAccountStatus("accounts.test", AccountStatus.CLOSED); + + // Assert + Assert.assertEquals(ResponseReason.ACCOUNT_NOT_FOUND, response); + } + + @Test + public void test_setAccountStatus_UNKNOWN_ERROR() { + // Arrange + Mockito.when(this.accountRepository.findByKey(Mockito.anyString())).thenReturn(new Account()); + Mockito.doThrow(new NullPointerException()).when(this.accountRepository).save(Mockito.any(Account.class)); + + // Act + ResponseReason response = this.classUnderTest.setAccountStatus("accounts.test", AccountStatus.CLOSED); + + // Assert + Assert.assertEquals(ResponseReason.UNKNOWN_ERROR, response); + } + + @Test + public void test_setAccountStatus_OK() { + // Arrange + Mockito.when(this.accountRepository.findByKey(Mockito.anyString())).thenReturn(new Account()); + + // Act + ResponseReason response = this.classUnderTest.setAccountStatus("accounts.test", AccountStatus.CLOSED); + + // Assert + Assert.assertEquals(ResponseReason.OK, response); + Mockito.verify(this.accountRepository, Mockito.times(1)) + .save(ArgumentMatchers.argThat((acc) -> AccountStatus.CLOSED.equals(acc.getStatus()))); + } +} diff --git a/src/test/java/de/financer/service/RecurringTransactionService_deleteRecurringTransactionTest.java b/src/test/java/de/financer/service/RecurringTransactionService_deleteRecurringTransactionTest.java new file mode 100644 index 0000000..635d1a9 --- /dev/null +++ b/src/test/java/de/financer/service/RecurringTransactionService_deleteRecurringTransactionTest.java @@ -0,0 +1,94 @@ +package de.financer.service; + +import de.financer.ResponseReason; +import de.financer.config.FinancerConfig; +import de.financer.dba.RecurringTransactionRepository; +import de.financer.model.RecurringTransaction; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Optional; + +@RunWith(MockitoJUnitRunner.class) +public class RecurringTransactionService_deleteRecurringTransactionTest { + @InjectMocks + private RecurringTransactionService classUnderTest; + + @Mock + private AccountService accountService; + + @Mock + private RuleService ruleService; + + @Mock + private RecurringTransactionRepository recurringTransactionRepository; + + @Mock + private FinancerConfig financerConfig; + + @Test + public void test_deleteRecurringTransaction_MISSING_RECURRING_TRANSACTION_ID() { + // Arrange + // Nothing to do + + // Act + final ResponseReason response = this.classUnderTest.deleteRecurringTransaction(null); + + // Assert + Assert.assertEquals(ResponseReason.MISSING_RECURRING_TRANSACTION_ID, response); + } + + @Test + public void test_deleteRecurringTransaction_INVALID_RECURRING_TRANSACTION_ID() { + // Arrange + // Nothing to do + + // Act + final ResponseReason response = this.classUnderTest.deleteRecurringTransaction("invalid"); + + // Assert + Assert.assertEquals(ResponseReason.INVALID_RECURRING_TRANSACTION_ID, response); + } + + @Test + public void test_deleteRecurringTransaction_RECURRING_TRANSACTION_NOT_FOUND() { + // Arrange + Mockito.when(this.recurringTransactionRepository.findById(Mockito.anyLong())).thenReturn(Optional.empty()); + + // Act + final ResponseReason response = this.classUnderTest.deleteRecurringTransaction("123"); + + // Assert + Assert.assertEquals(ResponseReason.RECURRING_TRANSACTION_NOT_FOUND, response); + } + + @Test + public void test_deleteRecurringTransaction_UNKNOWN_ERROR() { + // Arrange + Mockito.when(this.recurringTransactionRepository.findById(Mockito.anyLong())).thenReturn(Optional.of(new RecurringTransaction())); + Mockito.doThrow(new NullPointerException()).when(this.recurringTransactionRepository).deleteById(Mockito.anyLong()); + + // Act + final ResponseReason response = this.classUnderTest.deleteRecurringTransaction("123"); + + // Assert + Assert.assertEquals(ResponseReason.UNKNOWN_ERROR, response); + } + + @Test + public void test_deleteRecurringTransaction_OK() { + // Arrange + Mockito.when(this.recurringTransactionRepository.findById(Mockito.anyLong())).thenReturn(Optional.of(new RecurringTransaction())); + + // Act + final ResponseReason response = this.classUnderTest.deleteRecurringTransaction("123"); + + // Assert + Assert.assertEquals(ResponseReason.OK, response); + } +} diff --git a/src/test/java/de/financer/service/TransactionService_deleteTransactionTest.java b/src/test/java/de/financer/service/TransactionService_deleteTransactionTest.java new file mode 100644 index 0000000..f6febd5 --- /dev/null +++ b/src/test/java/de/financer/service/TransactionService_deleteTransactionTest.java @@ -0,0 +1,129 @@ +package de.financer.service; + +import de.financer.ResponseReason; +import de.financer.config.FinancerConfig; +import de.financer.dba.TransactionRepository; +import de.financer.model.Account; +import de.financer.model.AccountType; +import de.financer.model.Transaction; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.*; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.List; +import java.util.Optional; + +@RunWith(MockitoJUnitRunner.class) +public class TransactionService_deleteTransactionTest { + @InjectMocks + private TransactionService classUnderTest; + + @Mock + private AccountService accountService; + + @Mock + private RuleService ruleService; + + @Mock + private TransactionRepository transactionRepository; + + @Mock + private FinancerConfig financerConfig; + + @Before + public void setUp() { + this.ruleService.afterPropertiesSet(); + + Mockito.when(this.ruleService.getMultiplierFromAccount(Mockito.any())).thenCallRealMethod(); + Mockito.when(this.ruleService.getMultiplierToAccount(Mockito.any())).thenCallRealMethod(); + } + + @Test + public void test_deleteRecurringTransaction_MISSING_TRANSACTION_ID() { + // Arrange + // Nothing to do + + // Act + final ResponseReason response = this.classUnderTest.deleteTransaction(null); + + // Assert + Assert.assertEquals(ResponseReason.MISSING_TRANSACTION_ID, response); + } + + @Test + public void test_deleteRecurringTransaction_INVALID_TRANSACTION_ID() { + // Arrange + // Nothing to do + + // Act + final ResponseReason response = this.classUnderTest.deleteTransaction("invalid"); + + // Assert + Assert.assertEquals(ResponseReason.INVALID_TRANSACTION_ID, response); + } + + @Test + public void test_deleteRecurringTransaction_TRANSACTION_NOT_FOUND() { + // Arrange + Mockito.when(this.transactionRepository.findById(Mockito.anyLong())).thenReturn(Optional.empty()); + + // Act + final ResponseReason response = this.classUnderTest.deleteTransaction("123"); + + // Assert + Assert.assertEquals(ResponseReason.TRANSACTION_NOT_FOUND, response); + } + + @Test + public void test_deleteRecurringTransaction_UNKNOWN_ERROR() { + // Arrange + Mockito.when(this.transactionRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(createTransaction(AccountType.BANK, AccountType.EXPENSE))); + Mockito.doThrow(new NullPointerException()).when(this.transactionRepository).deleteById(Mockito.anyLong()); + + // Act + final ResponseReason response = this.classUnderTest.deleteTransaction("123"); + + // Assert + Assert.assertEquals(ResponseReason.UNKNOWN_ERROR, response); + } + + @Test + public void test_deleteRecurringTransaction_OK() { + // Arrange + Mockito.when(this.transactionRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(createTransaction(AccountType.BANK, AccountType.EXPENSE))); + + // Act + final ResponseReason response = this.classUnderTest.deleteTransaction("123"); + + // Assert + Assert.assertEquals(ResponseReason.OK, response); + + final InOrder inOrder = Mockito.inOrder(this.accountService); + + inOrder.verify(this.accountService).saveAccount(ArgumentMatchers.argThat((Account arg) -> Long.valueOf(50000L).equals(arg.getCurrentBalance()))); + inOrder.verify(this.accountService).saveAccount(ArgumentMatchers.argThat((Account arg) -> Long.valueOf(5000L).equals(arg.getCurrentBalance()))); + } + + private Transaction createTransaction(AccountType fromType, AccountType toType) { + final Transaction transaction = new Transaction(); + final Account fromAccount = new Account(); + final Account toAccount = new Account(); + + transaction.setFromAccount(fromAccount); + transaction.setToAccount(toAccount); + transaction.setAmount(Long.valueOf(10000L)); + + fromAccount.setCurrentBalance(Long.valueOf(40000L)); + toAccount.setCurrentBalance(Long.valueOf(15000L)); + + fromAccount.setType(fromType); + toAccount.setType(toType); + + return transaction; + } +}