Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
Loading items

Target

Select target project
  • deadlocker8/BudgetMaster
1 result
Select Git revision
Loading items
Show changes

Commits on Source 6

Showing
with 163 additions and 18 deletions
......@@ -47,7 +47,7 @@ public class AboutController extends BaseController
public String whatsNewModal(Model model)
{
final List<NewsEntry> newsEntries = new ArrayList<>();
newsEntries.add(NewsEntry.createWithLocalizationKey("mariaDB"));
newsEntries.add(NewsEntry.createWithLocalizationKey("transactionNameSuggestionsOrder"));
model.addAttribute(ModelAttributes.NEWS_ENTRIES, newsEntries);
return ReturnValues.WHATS_NEW;
......
......@@ -21,7 +21,7 @@ public enum EntityType implements LocalizedEnum
ICON("icon", "background-grey", ImportRequired.NONE, "icons", "icon"),
TRANSACTION_NAME_KEYWORD("transaction_name_keyword", "background-grey", ImportRequired.NONE, "keywords", "keyword"),
RECURRING_TRANSACTIONS("repeat", "background-orange-dark", ImportRequired.NONE, "recurring", "recurring"),
TRANSACTION_IMPORT("fas fa-file-csv", "background-orange-dark", ImportRequired.NONE, "transactionImport", "transactionImport");
TRANSACTION_IMPORT("fas fa-file-csv", "background-orange-dark", ImportRequired.NONE, "transactionImportSettings", "transactionImportSettings");
public enum ImportRequired
{
......
......@@ -45,6 +45,8 @@ public class Settings
private Boolean migrationDeclined;
private Boolean orderTransactionNameSuggestionsAlphabetically;
public Settings()
{
// empty
......@@ -73,6 +75,7 @@ public class Settings
defaultSettings.setInstalledVersionCode(0);
defaultSettings.setWhatsNewShownForCurrentVersion(false);
defaultSettings.setMigrationDeclined(false);
defaultSettings.setOrderTransactionNameSuggestionsAlphabetically(true);
return defaultSettings;
}
......@@ -301,6 +304,16 @@ public class Settings
this.migrationDeclined = migrationDeclined;
}
public Boolean getOrderTransactionNameSuggestionsAlphabetically()
{
return orderTransactionNameSuggestionsAlphabetically;
}
public void setOrderTransactionNameSuggestionsAlphabetically(Boolean orderTransactionNameSuggestionsAlphabetically)
{
this.orderTransactionNameSuggestionsAlphabetically = orderTransactionNameSuggestionsAlphabetically;
}
@Override
public String toString()
{
......@@ -326,6 +339,7 @@ public class Settings
", installedVersionCode=" + installedVersionCode +
", whatsNewShownForCurrentVersion=" + whatsNewShownForCurrentVersion +
", migrationDeclined=" + migrationDeclined +
", orderTransactionNameSuggestionsAlphabetically=" + orderTransactionNameSuggestionsAlphabetically +
'}';
}
}
\ No newline at end of file
......@@ -112,6 +112,10 @@ public class SettingsService
{
settings.setMigrationDeclined(defaultSettings.getMigrationDeclined());
}
if(settings.getOrderTransactionNameSuggestionsAlphabetically() == null)
{
settings.setOrderTransactionNameSuggestionsAlphabetically(defaultSettings.getOrderTransactionNameSuggestionsAlphabetically());
}
settingsRepository.save(settings);
}
......
......@@ -11,12 +11,13 @@ import java.util.List;
public final class TransactionsSettingsContainer implements SettingsContainer
{
private Boolean restActivated;
private Boolean orderTransactionNameSuggestionsAlphabetically;
private List<TransactionNameKeyword> keywords;
public TransactionsSettingsContainer(Boolean restActivated, List<TransactionNameKeyword> keywords)
public TransactionsSettingsContainer(Boolean restActivated, Boolean orderTransactionNameSuggestionsAlphabetically, List<TransactionNameKeyword> keywords)
{
this.restActivated = restActivated;
this.orderTransactionNameSuggestionsAlphabetically = orderTransactionNameSuggestionsAlphabetically;
this.keywords = keywords;
}
......@@ -33,6 +34,10 @@ public final class TransactionsSettingsContainer implements SettingsContainer
{
restActivated = false;
}
if(orderTransactionNameSuggestionsAlphabetically == null)
{
orderTransactionNameSuggestionsAlphabetically = false;
}
}
@Override
......@@ -59,6 +64,7 @@ public final class TransactionsSettingsContainer implements SettingsContainer
final Settings settings = settingsService.getSettings();
settings.setRestActivated(restActivated);
settings.setOrderTransactionNameSuggestionsAlphabetically(orderTransactionNameSuggestionsAlphabetically);
return settings;
}
......
......@@ -35,7 +35,7 @@ public interface TransactionRepository extends JpaRepository<Transaction, Intege
List<Transaction> findAllByTransferAccount(Account account);
List<Transaction> findAllByOrderByDateDesc();
List<Transaction> findAllByOrderByNameAsc();
Transaction findFirstByOrderByDate();
......
......@@ -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());
}
}
......@@ -269,6 +269,10 @@ settings.rest=Saldos anzeigen
settings.rest.deactivated=Aus
settings.rest.activated=An
settings.rest.description=Zeigt den Saldo des letzten Monats und des aktuellen Monatsendes in der Buchungsübersicht an
settings.transactionNameSuggestionOrder=Sortierung der Namensvorschläge
settings.transactionNameSuggestionOrder.deactivated=nach Nutzungshäufigkeit
settings.transactionNameSuggestionOrder.activated=alphabetisch
settings.transactionNameSuggestionOrder.description=Legt die Sortierung von Namensvorschlägen für Buchungen fest
settings.darkTheme=Design
settings.darkTheme.deactivated=Helles Design
settings.darkTheme.activated=Dunkles Design
......
......@@ -269,6 +269,10 @@ settings.rest=Show balances
settings.rest.deactivated=Off
settings.rest.activated=On
settings.rest.description=Show the balance of the last month and of the current month end in the transaction overview
settings.transactionNameSuggestionOrder=Order name suggestions
settings.transactionNameSuggestionOrder.deactivated=by frequency of use
settings.transactionNameSuggestionOrder.activated=alphabetically
settings.transactionNameSuggestionOrder.description=Defines how the transaction name suggestions are ordered.
settings.darkTheme=Theme
settings.darkTheme.deactivated=Light Theme
settings.darkTheme.activated=Dark Theme
......
......@@ -2,5 +2,5 @@ news.further.information=Weitere Informationen
news.all.releases=Alle veröffentlichten und geplanten Versionen:
news.detailed=Ausführliches Changelog (nur auf Englisch):
news.mariaDB.headline=Bugfix: MariaDB
news.mariaDB.description=Fehler beim Upload von Bildern bei der Verwendung von MariaDB behoben.
news.transactionNameSuggestionsOrder.headline=Neue Einstellungsoption für die Sortierung der Buchungsnamensvorschläge
news.transactionNameSuggestionsOrder.description=Neu Einstellungsoption, um festzulegen, wie die Vorschläge für Transaktionsnamen sortiert werden (alphabetisch oder nach Häufigkeit der Verwendung).
......@@ -2,5 +2,5 @@ news.further.information=Further information
news.all.releases=All published and planned releases:
news.detailed=Detailed changelog (english only):
news.mariaDB.headline=Bugfix: MariaDB
news.mariaDB.description=Fixed an error when uploading images when using MariaDB.
news.transactionNameSuggestionsOrder.headline=New settings option for transaction name suggestion ordering
news.transactionNameSuggestionsOrder.description=Added a new settings option to define how transaction name suggestions are ordered (alphabetically or by frequency of use).
......@@ -24,6 +24,7 @@ $(document).ready(function()
let nameElements = document.querySelectorAll('.autocomplete');
let autoCompleteInstances = M.Autocomplete.init(nameElements, {
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)
......
......@@ -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)
......
......@@ -13,16 +13,21 @@
<div class="table-container">
<div class="table-cell">
<div class="switch-cell-margin">${locale.getString("settings.rest")}</div>
<div class="switch-cell-margin">${locale.getString("settings.transactionNameSuggestionOrder")}</div>
</div>
<div class="table-cell table-cell-spacer"></div>
<div class="table-cell">
<@settingsMacros.switch "rest" "restActivated" settings.isRestActivated()/>
<@settingsMacros.switch "transactionNameSuggestionOrder" "orderTransactionNameSuggestionsAlphabetically" settings.getOrderTransactionNameSuggestionsAlphabetically()?? && settings.getOrderTransactionNameSuggestionsAlphabetically()/>
</div>
<div class="table-cell table-cell-spacer"></div>
<div class="table-cell">
<div class="switch-cell-margin">
<a class="btn btn-flat tooltipped text-default" data-position="bottom" data-tooltip="${locale.getString("settings.rest.description")}"><i class="material-icons">help_outline</i></a>
</div>
<div class="switch-cell-margin">
<a class="btn btn-flat tooltipped text-default" data-position="bottom" data-tooltip="${locale.getString("settings.transactionNameSuggestionOrder.description")}"><i class="material-icons">help_outline</i></a>
</div>
</div>
</div>
</div>
......
......@@ -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\"]");
}
}
......@@ -27,7 +27,7 @@ class TransactionSettingsContainerTest
@Test
void test_validate_valid()
{
final TransactionsSettingsContainer container = new TransactionsSettingsContainer(true, List.of());
final TransactionsSettingsContainer container = new TransactionsSettingsContainer(true, true, List.of());
final Errors errors = new BeanPropertyBindingResult(container, "container");
container.validate(errors);
......@@ -39,12 +39,13 @@ class TransactionSettingsContainerTest
@Test
void test_fixBooleans()
{
final TransactionsSettingsContainer container = new TransactionsSettingsContainer(null, List.of());
final TransactionsSettingsContainer container = new TransactionsSettingsContainer(null, null, List.of());
container.fixBooleans();
assertThat(container)
.hasFieldOrPropertyWithValue("restActivated", false);
.hasFieldOrPropertyWithValue("restActivated", false)
.hasFieldOrPropertyWithValue("orderTransactionNameSuggestionsAlphabetically", false);
}
@Test
......@@ -54,10 +55,11 @@ class TransactionSettingsContainerTest
Mockito.when(settingsService.getSettings()).thenReturn(defaultSettings);
final TransactionsSettingsContainer container = new TransactionsSettingsContainer(false, List.of());
final TransactionsSettingsContainer container = new TransactionsSettingsContainer(false, false, List.of());
final Settings updatedSettings = container.updateSettings(settingsService);
assertThat(updatedSettings)
.hasFieldOrPropertyWithValue("restActivated", false);
.hasFieldOrPropertyWithValue("restActivated", false)
.hasFieldOrPropertyWithValue("orderTransactionNameSuggestionsAlphabetically", false);
}
}