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;
+ }
+}