diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionRepository.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionRepository.java index 467e0d6330241371143410addfbf8efd027e3332..d5fbacc8151f44cb3b962d505df82e42749fa6de 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionRepository.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionRepository.java @@ -35,7 +35,7 @@ public interface TransactionRepository extends JpaRepository<Transaction, Intege List<Transaction> findAllByTransferAccount(Account account); - List<Transaction> findAllByOrderByDateDesc(); + List<Transaction> findAllByOrderByNameAsc(); Transaction findFirstByOrderByDate(); diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionService.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionService.java index a54b1cdb1bbd97133d69f91ac5fc81e2c033a6b9..70f4b06ffcc965e5a1f20d4b9264709108ddec77 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionService.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionService.java @@ -28,7 +28,9 @@ import java.text.MessageFormat; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import static java.time.temporal.TemporalAdjusters.lastDayOfMonth; @@ -44,6 +46,7 @@ public class TransactionService implements Resettable private final RepeatingOptionRepository repeatingOptionRepository; private final CategoryService categoryService; private final TagService tagService; + private final SettingsService settingsService; @Autowired public TransactionService(TransactionRepository transactionRepository, RepeatingOptionRepository repeatingOptionRepository, CategoryService categoryService, TagService tagService, SettingsService settingsService) @@ -52,6 +55,7 @@ public class TransactionService implements Resettable this.repeatingOptionRepository = repeatingOptionRepository; this.categoryService = categoryService; this.tagService = tagService; + this.settingsService = settingsService; } public TransactionRepository getRepository() @@ -300,11 +304,24 @@ public class TransactionService implements Resettable public String getNameSuggestionsJson() { - final List<Transaction> allByOrderByDateDesc = getRepository().findAllByOrderByDateDesc(); - final List<String> nameSuggestions = allByOrderByDateDesc.stream() + final List<Transaction> allOrderedByNameAsc = getRepository().findAllByOrderByNameAsc(); + final List<String> names = allOrderedByNameAsc.stream() .map(Transaction::getName) - .distinct() .toList(); - return GSON.toJson(nameSuggestions); + + List<String> nameSuggestions = names; + + if(!settingsService.getSettings().getOrderTransactionNameSuggestionsAlphabetically()) + { + nameSuggestions = names.stream() + .collect(Collectors.groupingBy(e -> e, Collectors.counting())) + .entrySet() + .stream() + .sorted(Map.Entry.<String, Long>comparingByValue().reversed().thenComparing(Map.Entry.comparingByKey())) + .map(Map.Entry::getKey) + .toList(); + } + + return GSON.toJson(nameSuggestions.stream().distinct().toList()); } } diff --git a/BudgetMasterServer/src/main/resources/static/js/transactions.js b/BudgetMasterServer/src/main/resources/static/js/transactions.js index 85a185d073252eed8d00f6fd91c1e3c8feed5bf6..fa31242f4973608b638d42f7df27bc7dafe1b6d3 100644 --- a/BudgetMasterServer/src/main/resources/static/js/transactions.js +++ b/BudgetMasterServer/src/main/resources/static/js/transactions.js @@ -13,6 +13,7 @@ $(document).ready(function() let elements = document.querySelectorAll('#transaction-name'); let autoCompleteInstances = M.Autocomplete.init(elements, { data: transactionNameSuggestions, + sortFunction: function(a,b, inputString) {return false;} }); // prevent tab traversal for dropdown (otherwise "tab" needs to be hit twice to jump from name input to amount input) diff --git a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceTest.java b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceTest.java index 16b0770dfbb9250e3d938cca8ee712a17afab734..907cffd7648f38762c9efc4537dd655dadeb89cf 100644 --- a/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceTest.java +++ b/BudgetMasterServer/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceTest.java @@ -4,6 +4,8 @@ import de.deadlocker8.budgetmaster.accounts.Account; import de.deadlocker8.budgetmaster.accounts.AccountType; import de.deadlocker8.budgetmaster.categories.Category; import de.deadlocker8.budgetmaster.categories.CategoryType; +import de.deadlocker8.budgetmaster.settings.Settings; +import de.deadlocker8.budgetmaster.settings.SettingsService; import de.deadlocker8.budgetmaster.transactions.Transaction; import de.deadlocker8.budgetmaster.transactions.TransactionRepository; import de.deadlocker8.budgetmaster.transactions.TransactionService; @@ -15,6 +17,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -31,6 +34,9 @@ class TransactionServiceTest @Mock private TransactionRepository transactionRepository; + @Mock + private SettingsService settingsService; + @InjectMocks private TransactionService transactionService; @@ -104,4 +110,85 @@ class TransactionServiceTest assertThat(transaction).hasFieldOrPropertyWithValue("amount", 500) .hasFieldOrPropertyWithValue("isExpenditure", false); } + + @Test + void test_getNameSuggestionsJson_sortAlphabetically() + { + final Settings settings = Settings.getDefault(); + + Mockito.when(settingsService.getSettings()).thenReturn(settings); + + final Transaction transaction1 = new Transaction(); + transaction1.setID(1); + transaction1.setName("ABC"); + transaction1.setAmount(700); + transaction1.setCategory(CATEGORY_CUSTOM); + transaction1.setAccount(ACCOUNT); + transaction1.setIsExpenditure(false); + + final Transaction transaction2 = new Transaction(); + transaction2.setID(1); + transaction2.setName("XYZ"); + transaction2.setAmount(700); + transaction2.setCategory(CATEGORY_CUSTOM); + transaction2.setAccount(ACCOUNT); + transaction2.setIsExpenditure(false); + + final Transaction transaction3 = new Transaction(); + transaction3.setID(1); + transaction3.setName("XYZ"); + transaction3.setAmount(700); + transaction3.setCategory(CATEGORY_CUSTOM); + transaction3.setAccount(ACCOUNT); + transaction3.setIsExpenditure(false); + + Mockito.when(transactionRepository.findAllByOrderByNameAsc()).thenReturn(List.of(transaction1, transaction2, transaction3)); + + assertThat(transactionService.getNameSuggestionsJson()).isEqualTo("[\"ABC\",\"XYZ\"]"); + } + + @Test + void test_getNameSuggestionsJson_sortByFrequencyOfUse() + { + final Settings settings = Settings.getDefault(); + settings.setOrderTransactionNameSuggestionsAlphabetically(false); + + Mockito.when(settingsService.getSettings()).thenReturn(settings); + + final Transaction transaction1 = new Transaction(); + transaction1.setID(1); + transaction1.setName("ABC"); + transaction1.setAmount(700); + transaction1.setCategory(CATEGORY_CUSTOM); + transaction1.setAccount(ACCOUNT); + transaction1.setIsExpenditure(false); + + final Transaction transaction2 = new Transaction(); + transaction2.setID(1); + transaction2.setName("XYZ"); + transaction2.setAmount(700); + transaction2.setCategory(CATEGORY_CUSTOM); + transaction2.setAccount(ACCOUNT); + transaction2.setIsExpenditure(false); + + final Transaction transaction3 = new Transaction(); + transaction3.setID(1); + transaction3.setName("XYZ"); + transaction3.setAmount(700); + transaction3.setCategory(CATEGORY_CUSTOM); + transaction3.setAccount(ACCOUNT); + transaction3.setIsExpenditure(false); + + final Transaction transaction4 = new Transaction(); + transaction4.setID(1); + transaction4.setName("LOREM"); + transaction4.setAmount(700); + transaction4.setCategory(CATEGORY_CUSTOM); + transaction4.setAccount(ACCOUNT); + transaction4.setIsExpenditure(false); + + Mockito.when(transactionRepository.findAllByOrderByNameAsc()).thenReturn(List.of(transaction1, transaction2, transaction3, transaction4)); + + assertThat(transactionService.getNameSuggestionsJson()).isEqualTo("[\"XYZ\",\"ABC\",\"LOREM\"]"); + } }